How to Build a CRUD App in Vanilla PHP

Introduction

During a recent technical assessment, I was tasked to develop a simple CRUD events management system in PHP. I planned on using Laravel as I have always done, after all, it is really easy. However, I run into a few problems and was unable to proceed beyond creating a new Laravel project. My only other option was to do the app in vanilla PHP, however, given that I had been using Laravel for a long time, I had totally forgotten how to accomplish this simple task. For anyone else out there like me, here is a simple step by step way of developing a simple CRUD application without any frameworks.

What do I hope to achieve?

  • Follow the principle of separation of concerns as much as possible
  • Create a script to handle the database connection, another script for running all database migrations.
  • Have a class to handle all database transactions. For this case, we will limit this to inserting, viewing, updating and deleting items from the database.
  • Create a dynamic web app that will allow users to perform the CRUD operationsPrerequisites
  • Basic knowledge of PHP, HTML, and CSS
  • A local PHP and MySQL develop environment eg  MAMP, vagrant.
  • I will begin by taking you through what the file structure will look like. If you would like to look at the full project you can find it here
  • File structure
  • I will first show you what the file structure looks like:Events
  • app
  • Models
  • event.php
  • Templates
  •  app.php
  •  create.php
  •  delete.php
  •  edit.php
  •  update.php
  •  index.php
  • View.php
  •  database migrations.php
  • migrations (Folder containing the migration files)
  • scripts
  • create_migration.php
  • migrate.php
  • config.php
  • Migrations_list.php

Connect to database

First, we need to create a connection to the database so we can be able to save the data. I will be using a MySQL database which I will call events.We will do all the configurations in the config.php file.PHP has an inbuilt class, PDO, for handling database connections.[pastacode lang="php" manual="%3C%3Fphp%0Aclass%20PDOConfig%20extends%20PDO%20%7B%0A%20%0A%20%20%20private%20%24engine%3B%0A%20%20%20private%20%24host%3B%0A%20%20%20private%20%24database%3B%0A%20%20%20private%20%24user%3B%0A%20%20%20private%20%24pass%3B%0A%20%20%20private%20%24port%3B%0A%20%20%20private%20%24db%3B%0A%0A%20%0A%20%20%20public%20function%20__construct()%7B%0A%20%20%20%20%20%20%20%24this-%3Eengine%20%3D%20'mysql'%3B%0A%20%20%20%20%20%20%20%24this-%3Ehost%20%3D%20'127.0.0.1'%3B%0A%20%20%20%20%20%20%20%24this-%3Edatabase%20%3D%20'events'%3B%0A%20%20%20%20%20%20%20%24this-%3Euser%20%3D%20'root'%3B%0A%20%20%20%20%20%20%20%24this-%3Epass%20%3D%20'root'%3B%0A%20%20%20%20%20%20%20%24this-%3Eport%20%3D%20'8889'%3B%0A%20%20%20%20%20%20%20%24dsn%20%3D%20%24this-%3Eengine.'%3Adbname%3D'.%24this-%3Edatabase.'%3Bhost%3D'.%24this-%3Ehost.'%3Bport%3D'.%24this-%3Eport%3B%0A%20%20%20%20%20%20%20parent%3A%3A__construct(%20%24dsn%2C%20%24this-%3Euser%2C%20%24this-%3Epass%20)%3B%20%20%0A%20%20%20%7D%0A%7D%0A%3F%3E%0A" message="" highlight="" provider="manual"/]It is, however, not advisable to pass in the database parameters as I did above, they should always be passed in as environment variables.

Database transactions

We will then define a class that will handle all the database transactions which means we only need to call the config.php in this one file, instead of every timewe need to interact with the database. I have defined INSERT, UPDATE, SELECT, and DELETE statements here. Notice that I make use of prepared statements to provide a level of security against SQL injection.[pastacode lang="php" manual="%3C%3Fphp%0A%20%20%20require_once('..%2F..%2Fconfig.php')%3B%0A%0A%20%20%20class%20DatabaseTranscations%20extends%20PDOStatement%20%7B%0A%20%20%20%20%20%20%20private%20%24connection%3B%0A%0A%20%20%20%20%20%20%20public%20function%20__construct()%0A%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20private%20function%20connection()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%24connection%20%3D%20new%20PDOConfig()%3B%0A%20%20%20%20%20%20%20%20%20%20%20if(%24connection%20%3D%3D%3D%20false)%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20echo%20%22ERROR%3A%20Could%20not%20connect.%20%22%20.%20mysqli_connect_error()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20return%20%24connection%3B%0A%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20public%20function%20insert(%24event_name%2C%20%24description)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%24sql%20%3D%20%22INSERT%20INTO%20events(event_name%2C%20description)%20VALUES%20(%3F%2C%20%3F)%22%3B%0A%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%24connection%20%3D%20%24this-%3Econnection()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%24statement%20%3D%20%24connection-%3Eprepare(%24sql)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%24statement-%3EbindParam(1%2C%20%24event_name%2C%20PDO%3A%3APARAM_STR)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%24statement-%3EbindParam(2%2C%20%24description%2C%20PDO%3A%3APARAM_STR)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%24statement-%3Eexecute()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%24connection%20%3D%20null%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20true%3B%0A%20%20%20%20%20%20%20%7D%20catch%20(PDOException%20%24e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20echo%20%24e-%3EgetMessage()%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20public%20function%20select(%24id%20%3D%20null)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20if%20(isset(%24id))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24sql%20%3D%20%22SELECT%20*%20FROM%20events%20WHERE%20id%20%3D%20%3Aid%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24connection%20%3D%20%24this-%3Econnection()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24statement%20%3D%20%24connection-%3Eprepare(%24sql)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24statement-%3EbindValue('%3Aid'%2C%20%24id)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24statement-%3Eexecute()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24result%20%3D%20%24statement-%3Efetch(PDO%3A%3AFETCH_ASSOC)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24connection%20%3D%20null%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20%24result%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(PDOException%20%24e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20echo%20%24e-%3EgetMessage()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24sql%20%3D%20%20%22SELECT%20*%20FROM%20events%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24connection%20%3D%20%24this-%3Econnection()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24statement%20%3D%20%24connection-%3Equery(%24sql)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24result%20%3D%20%24statement-%3EfetchAll()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24connection%20%3D%20null%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20%24result%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(PDOException%20%24e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20echo%20%24e-%3EgetMessage()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20public%20function%20update(%24event_name%2C%20%24description%2C%20%24id)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%24sql%20%3D%20%22UPDATE%20events%20set%20event_name%20%3D%20%3F%2C%20description%20%3D%20%3F%20WHERE%20id%20%3D%20%3F%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24connection%20%3D%20%24this-%3Econnection()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24statement%20%3D%20%24connection-%3Eprepare(%24sql)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24statement-%3EbindParam(1%2C%20%24event_name%2C%20PDO%3A%3APARAM_STR)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24statement-%3EbindParam(2%2C%20%24description%2C%20PDO%3A%3APARAM_STR)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24statement-%3EbindParam(3%2C%20%24id%2C%20PDO%3A%3APARAM_INT)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24statement-%3Eexecute()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24connection%20%3D%20null%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20true%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(PDOException%20%24e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20echo%20%24e-%3EgetMessage()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20public%20function%20delete(%24id)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%24sql%20%3D%20%22DELETE%20FROM%20events%20WHERE%20id%20%3D%20%3F%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24connection%20%3D%20%24this-%3Econnection()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24statement%20%3D%20%24connection-%3Eprepare(%24sql)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24statement-%3EbindParam(1%2C%20%24id%2C%20PDO%3A%3APARAM_INT)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24statement-%3Eexecute()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24connection%20%3D%20null%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20true%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(PDOException%20%24e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20echo%20%24e-%3EgetMessage()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A" message="" highlight="" provider="manual"/]

Create tables

I created a script, create_migration.php to generate the migration files. When this script is run with the table name, it generates the migration file for creating that table.[pastacode lang="php" manual="%3C%3Fphp%0A%0A%24opt%20%3D%20't%3A'%3B%0A%24options%20%3D%20getopt(%24opt)%3B%0Aif%20(!%24options)%20%7B%0A%20%20%20echo%20%22Migrations%20not%20created%20please%20provide%20a%20table%20name%22%3B%0A%7D%20else%20%7B%0A%20%20%20%24table_name%20%3D%20%24options%20%3F%20%24options%5B't'%5D%20%3A%20%22%22%3B%0A%0A%20%20%20%24time%20%3D%20time()%3B%0A%20%20%20%24date%20%3D%20date('Y_m_d')%3B%0A%20%20%20%24time_stamp%20%3D%20%24date%20.%20%22_%22%20.%20%24time%3B%0A%20%20%20%24file_name%20%3D%20%24time_stamp%20.%20%22_create_%22%20.%20%24table_name%20.%20%22_table.php%22%3B%0A%20%20%20%24table%20%3D%20ucwords(%24table_name)%3B%0A%20%20%20%24migrate_table%20%3D%20%22Create%22.%24table.%22Table%22%3B%0A%20%20%0A%20%20%20%24data%20%3D%0A%20%20%20%20%20%20%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%3C%3Fphp%0A%20%20%20%20%20%20%20%20%20%20%20require_once(__DIR__.'%2F..%2Fconfig.php')%3B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20class%20%22%20.%20%24migrate_table%20.%20%22%20%7B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20private%20function%20connection()%20%7B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%24connection%20%3D%20new%20PDOConfig()%3B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(%5C%24connection%20%3D%3D%3D%20false)%20%7B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20echo%20'ERROR%3A%20Could%20not%20connect.%20mysqli_connect_error()'%3B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20%5C%24connection%3B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20public%20function%20createTable()%20%7B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%24table_name%20%3D%20%22.%20%22%20%20'%24table_name'%20%20%22%20.%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%24sql%20%3D%20'CREATE%20TABLE%20%60%24table_name%60%20(%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20id%20INT%20AUTO_INCREMENT%20PRIMARY%20KEY%2C%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20created_at%20TIMESTAMP%20DEFAULT%20CURRENT_TIMESTAMP)'%3B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%24connection%20%3D%20%5C%24this-%3Econnection()%3B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%24statement%20%3D%20%5C%24connection-%3Eprepare(%5C%24sql)%3B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%24statement-%3Eexecute()%3B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%24connection%20%3D%20null%3B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20true%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(PDOException%20%5C%24e)%20%7B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20echo%20%5C%24e-%3EgetMessage()%3B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20public%20function%20dropTable()%20%7B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%24table_name%20%3D%20%22.%20%22%20%20'%24table_name'%20%20%22%20.%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%24sql%20%3D%20'DROP%20TABLE%20IF%20EXISTS%20%60%24table_name%60'%3B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%24connection%20%3D%20%5C%24this-%3Econnection()%3B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%24statement%20%3D%20%5C%24connection-%3Eprepare(%5C%24sql)%3B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%24statement-%3Eexecute()%3B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%5C%24connection%20%3D%20null%3B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20true%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(PDOException%20%5C%24e)%20%7B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20echo%20%5C%24e-%3EgetMessage()%3B%5Cn%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%3F%3E%0A%20%20%20%20%20%20%20%22%0A%20%20%20%3B%0A%20%20%20file_put_contents(__DIR__.%22%2F..%2Fmigrations%22.%22%2F%22.%24file_name%2C%20%24data)%3B%0A%7D%0A%3F%3E%0A" message="" highlight="" provider="manual"/]

Migrations

To run my migrations, I run the script below, migrate.php.If I want to run all migrations, I run it without any flags otherwise, I run it with the file name of the migration to run.[pastacode lang="php" manual="%3C%3Fphp%0Arequire%20__DIR__.%22%2F..%2Fdatabase%2Fmigrations.php%22%3B%0Arequire%20__DIR__.%22..%2F..%2Fmigrations%2F2020_01_28_1580251805_create_venues_table.php%22%3B%0Arequire%20__DIR__.%22..%2F..%2Fmigrations%2F2020_01_29_1580256901_create_books_table.php%22%3B%0Arequire%20__DIR__.%22..%2F..%2Fmigrations%2F2020_01_28_1580250049_create_users_table.php%22%3B%0Arequire%20__DIR__.%22..%2F..%2Fmigrations%2F2020_01_29_1580262222_create_houses_table.php%22%3B%0Arequire%20__DIR__.%22..%2F..%2Fmigrations%2F2020_01_30_1580402897_create_teachers_table.php%22%3B%0Arequire%20__DIR__.%22..%2F..%2Fmigrations%2F2020_01_30_1580402811_create_subject_table.php%22%3B%0Arequire%20__DIR__.%22..%2F..%2Fmigrations%2F2020_01_30_1580418760_create_marks_table.php%22%3B%0A%0A%24opt%20%3D%20'm%3A'%3B%0A%24options%20%3D%20getopt(%24opt)%3B%0A%24file_name%20%3D%20%24options%20%3F%20%24options%5B'm'%5D%20%3A%20%22%22%3B%0A%24migrations%20%3D%20%5B%5D%3B%0A%24hashed_migration%20%3D%20new%20HashMigrations()%3B%0A%0Aif%20(!%24options)%20%7B%0A%20%20%20%24migrations_files%20%3D%20array_diff(scandir((__DIR__.%22%2F..%2Fmigrations%22))%2C%20%5B'..'%2C%20'.'%5D)%3B%0A%20%20%20foreach%20(%24migrations_files%20as%20%24migration_file)%20%7B%0A%20%20%20%20%20%20%20%24migration_file_path%20%3D%20__DIR__.%22..%2F..%2Fmigrations%22.%22%2F%22.%24migration_file%3B%0A%0A%20%20%20%20%20%20%20%24file1%20%3D%20preg_replace('%2F%5B0-9%5D%2F'%2C''%2C%24migration_file)%3B%0A%20%20%20%20%20%20%20%24file2%20%3D%20explode(%22_%22%2C%20%24file1)%3B%0A%20%20%20%20%20%20%20%24file3%20%3D%20implode(%22%20%22%2C%20%24file2)%3B%0A%20%20%20%20%20%20%20%24file4%20%3D%20ucwords(%24file3)%3B%0A%20%20%20%20%20%20%20%24file5%20%3D%20str_replace(%22%20%22%2C%20%22%22%2C%20%24file4)%3B%0A%20%20%20%20%20%20%20%24file6%20%3D%20str_replace(%22php%22%2C%20%22%22%2C%20%24file5)%3B%0A%20%20%20%20%20%20%20%24file7%20%3D%20str_replace(%22.%22%2C%20%22%22%2C%20%24file6)%3B%0A%20%20%20%20%20%20%20%24class_name%20%3D%20%24file7%3B%0A%20%20%20%20%20%20%20%24class%20%3D%20new%20%24class_name%3B%0A%20%20%20%20%20%20%0A%20%20%20%20%20%20%20if(%24hashed_migration-%3EmigrationExists(%24migration_file)%20%26%26%20%24hashed_migration-%3EcompareFileContents(%24migration_file))%7B%0A%20%20%20%20%20%20%20%20%20%20%20continue%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20elseif%20(%24hashed_migration-%3EmigrationExists(%24migration_file)%20%26%26%20!%24hashed_migration-%3EcompareFileContents(%24migration_file))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%24created%20%3D%20%24class-%3EcreateTable()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%24hashed_migration-%3EUpdateFileContentsHash(%24migration_file)%3B%0A%20%20%20%20%20%20%20%20%20%20%20echo%20%22Migration%20%22.%24migration_file.%22%20has%20been%20run.%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20continue%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20else%7B%0A%20%20%20%20%20%20%20%20%20%20%20%24created%20%3D%20%24class-%3EcreateTable()%3B%0A%20%20%20%20%20%20%20%20%20%20%20if%20(%24created)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24hashed_migration-%3EstoreHash(%24migration_file_path)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20echo%20%22Migration%20%22.%24migration_file.%22%20has%20been%20run.%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20echo%20%22Couldnot%20run%20migration%22.%20%24migration_file%20.%22%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20continue%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%7D%20else%20%7B%0A%20%20%20%24migration_file%20%3D%20%24file_name%3B%0A%20%20%20%24migration_file%20%3D%20__DIR__.%22..%2F..%2Fmigrations%22.%22%2F%22.%24migration_file%3B%0A%0A%20%20%20%24file1%20%3D%20preg_replace('%2F%5B0-9%5D%2F'%2C''%2C%24migration_file)%3B%0A%20%20%20%24file2%20%3D%20explode(%22_%22%2C%20%24file1)%3B%0A%20%20%20%24file3%20%3D%20implode(%22%20%22%2C%20%24file2)%3B%0A%20%20%20%24file4%20%3D%20ucwords(%24file3)%3B%0A%20%20%20%24file5%20%3D%20str_replace(%22%20%22%2C%20%22%22%2C%20%24file4)%3B%0A%20%20%20%24file6%20%3D%20str_replace(%22php%22%2C%20%22%22%2C%20%24file5)%3B%0A%20%20%20%24file7%20%3D%20str_replace(%22.%22%2C%20%22%22%2C%20%24file6)%3B%0A%20%20%20%24class_name%20%3D%20%24file7%3B%0A%20%20%20%24class%20%3D%20new%20%24class_name%3B%0A%0A%20%20%20if(%24hashed_migration-%3EmigrationExists(%24migration_file)%20%26%26%20%24hashed_migration-%3EcompareFileContents(%24migration_file))%7B%0A%20%20%20%20%20%20%20return%3B%0A%20%20%20%7D%0A%0A%20%20%20elseif%20(%24hashed_migration-%3EmigrationExists(%24migration_file)%20%26%26%20!%24hashed_migration-%3EcompareFileContents(%24migration_file))%20%7B%0A%20%20%20%20%20%20%20%24created%20%3D%20%24class-%3EcreateTable()%3B%0A%20%20%20%20%20%20%20%24hashed_migration-%3EUpdateFileContentsHash(%24migration_file)%3B%0A%20%20%20%20%20%20%20echo%20%22Migration%20%22.%24migration_file.%22%20has%20been%20run.%22%3B%0A%20%20%20%20%20%20%20return%20true%3B%0A%20%20%20%7D%0A%0A%20%20%20else%7B%0A%20%20%20%20%20%20%20%24created%20%3D%20%24class-%3EcreateTable()%3B%0A%20%20%20%20%20%20%20if%20(%24created)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%24hashed_migration-%3EstoreHash(%24migration_file_path)%3B%0A%20%20%20%20%20%20%20%20%20%20%20echo%20%22Migration%20%22.%24migration_file.%22%20has%20been%20run.%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20true%3B%0A%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20echo%20%22Couldnot%20run%20migration%22.%20%24migration_file%20.%22%22%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20return%20true%3B%0A%20%20%20%7D%0A%7D%0A%0A%24hashed_migration-%3EcheckForUpdate()%3B%0A%0A" message="" highlight="" provider="manual"/]A little a bit about this script, I have used the concept of the hash table to find which migrations have been run or have changed and which haven’t been run. Only the migrations that have either changed or not been run will run. To help with making this check and also running the migrations, I use the HashMigrations class in the hash_migrations.php file.Within this class, I have methods which:

  • Create the hash for both the migrations file name and contents of the migrations file
  • Save the hashed migrations file contents in the associative array with the hashed migrations file name as the key. This array contains all the migrations that have been run.
  • Update the hashed migrations file contents
  • Check if the migrations file contents have changed so that the associative array can be updated according

Check if a migration has been run before.[pastacode lang="php" manual="%3C%3Fphp%0Arequire%20__DIR__.%22%2Fmigrations_list.php%22%3B%0Aclass%20HashMigrations%20%7B%0A%20%20%20public%20%24migrations_array%3B%0A%20%20%20private%20%24stored_migrations_array%3B%0A%0A%20%20%20private%20function%20getMigrationsArray()%20%7B%0A%20%20%20%20%20%20%20%24file_contents%20%3D%20file_get_contents(__DIR__.%22%2F..%2Fmigrations_list.json%22)%3B%0A%20%20%20%20%20%20%20return%20json_decode(%24file_contents%2C%20true)%3B%0A%20%20%20%7D%0A%0A%20%20%20public%20function%20__construct()%20%7B%0A%20%20%20%20%20%20%20%24this-%3Estored_migrations_array%20%3D%20%24this-%3EgetMigrationsArray()%3B%0A%20%20%20%20%20%20%20%24this-%3Emigrations_array%20%3D%20%24this-%3EgetMigrationsArray()%3B%0A%0A%20%20%20%7D%0A%0A%20%20%20private%20function%20updateMigrationsArray()%20%7B%0A%20%20%20%20%20%20%20%24migration_array%20%3D%20json_encode(%24this-%3Emigrations_array)%3B%0A%20%20%20%20%20%20%20%24migrations%20%3D%20file_put_contents(__DIR__.%22%2F..%2Fmigrations_list.json%22%2C%20%24migration_array)%3B%0A%20%20%20%20%20%20%20if%20(%24migrations)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20true%3B%0A%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%0A%20%20%20public%20function%20checkForUpdate()%20%7B%0A%20%20%20%20%20%20%20if%20(%24this-%3Estored_migrations_array%20%3D%3D%3D%20%24this-%3Emigrations_array)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%3B%0A%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20%24this-%3EupdateMigrationsArray()%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%0A%20%20%20private%20function%20hashFileContents(%24file)%20%7B%0A%20%20%20%20%20%20%20%24hash%20%3D%20hash_file(%22sha1%22%2C%20%24file)%3B%0A%20%20%20%20%20%20%20if%20(!%24hash)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20throw%20new%20%5CErrorException(%22File%20does%20not%20exist%22)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20return%20%24hash%3B%0A%20%20%20%7D%0A%0A%20%20%20private%20function%20hashFileName(%24name)%20%7B%0A%20%20%20%20%20%20%20%24hash%20%3D%20hash(%22sha1%22%2C%20%24name)%3B%0A%20%20%20%20%20%20%20if%20(!%24hash)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20throw%20new%20%5CErrorException(%22File%20does%20not%20exist%22)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20return%20%24hash%3B%0A%20%20%20%7D%0A%0A%20%20%20public%20function%20storeHash(%24file)%20%7B%0A%20%20%20%20%20%20%20%24hash_file_name%20%3D%20%24this-%3EhashFileName(%24file)%3B%0A%20%20%20%20%20%20%20%24hash_content%20%3D%20%24this-%3EhashFileContents(%24file)%3B%0A%20%20%20%20%20%20%20%24this-%3Emigrations_array%5B%24hash_file_name%5D%20%3D%20%24hash_content%3B%0A%20%20%20%7D%0A%0A%20%20%20public%20function%20migrationExists(%24hash)%20%7B%0A%20%20%20%20%20%20%20if%20(isset(%24this-%3Emigrations_array%5B%24hash%5D))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20true%3B%0A%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%0A%20%20%20public%20function%20compareFileContents%20(%24file)%20%7B%0A%20%20%20%20%20%20%20%24hash%20%3D%20%24this-%3EhashFileName(%24file)%3B%0A%0A%20%20%20%20%20%20%20if%20(!%24this-%3EmigrationExists(%24hash))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20throw%20new%20%5CErrorException(%22Migration%20does%20not%20exist%22)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%24new_file_content_hash%20%3D%20%24this-%3EhashFileContents(%24file)%3B%0A%20%20%20%20%20%20%20%24old_file_content_hash%20%3D%20%24this-%3Emigrations_array%5B%24hash%5D%3B%0A%20%20%20%20%20%20%20if%20(%24new_file_content_hash%20%3D%3D%20%24old_file_content_hash)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20true%3B%0A%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%0A%20%20%20public%20function%20UpdateFileContentsHash(%24file)%20%7B%0A%20%20%20%20%20%20%20%24hashed_file_name%20%3D%20%24this-%3EhashFileName(%24file)%3B%0A%20%20%20%20%20%20%20%24hash_content%20%3D%20%24this-%3EhashFileContents(%24file)%3B%0A%20%20%20%20%20%20%20%24this-%3Emigrations_array%5B%24hashed_file_name%5D%20%3D%20%24hash_content%3B%0A%20%20%20%20%20%20%20return%20true%3B%0A%20%20%20%7D%0A%7D%0A" message="" highlight="" provider="manual"/]When the migrations are run, we check if a particular migration has been run before, if yes we check if the contents of the migrations file have changed, if yes we run the migrations otherwise we skip that migration. If the migration has not been run before we run the migration, hash it and add it to the migrations_list.

Add the CRUD

Next, we will add the functionality for the CRUD. I have done this in the event.php.[pastacode lang="php" manual="%3C%3Fphp%0A%0Arequire%20'..%2F..%2Fdatabase.php'%3B%0A%0Aclass%20Event%20%7B%0A%20%20%20public%20%24event_name%3B%0A%20%20%20public%20%24description%3B%0A%20%20%20private%20%24db%3B%0A%20%20%20public%20function%20__construct()%20%7B%0A%20%20%20%7D%0A%0A%20%20%20public%20function%20addEvent(%24event_name%2C%20%24description)%20%7B%0A%20%20%20%20%20%20%20%24event_name%20%3D%20filter_var(%24event_name%2C%20FILTER_SANITIZE_STRING)%3B%0A%20%20%20%20%20%20%20%24description%20%3D%20filter_var(%24description%2C%20FILTER_SANITIZE_STRING)%3B%0A%0A%20%20%20%20%20%20%20%24db%20%3D%20new%20DatabaseTranscations()%3B%0A%20%20%20%20%20%20%20%24inserted%20%3D%20%24db-%3Einsert(%24event_name%2C%20%24description)%3B%0A%20%20%20%20%20%20%20if%20(%24inserted)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20%22Successfully%20inserted%22%3B%0A%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20%22Something%20went%20wrong%20insertion%20didnot%20happen%22%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%0A%20%20%20public%20function%20viewEvents()%20%7B%0A%20%20%20%20%20%20%20%24db%20%3D%20new%20DatabaseTranscations()%3B%0A%20%20%20%20%20%20%20%24result%20%3D%20%24db-%3Eselect()%3B%0A%20%20%20%20%20%20%20if%20(%24result)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20%24result%3B%0A%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20%22No%20results%20returned%22%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%0A%20%20%20public%20function%20viewEvent(%24id)%20%7B%0A%20%20%20%20%20%20%20%24id%20%3D%20filter_var(%24id%2C%20FILTER_SANITIZE_NUMBER_INT)%3B%0A%0A%20%20%20%20%20%20%20%24db%20%3D%20new%20DatabaseTranscations()%3B%0A%20%20%20%20%20%20%20%24result%20%3D%20%24db-%3Eselect(%24id)%3B%0A%20%20%20%20%20%20%20if%20(%24result)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20%24result%3B%0A%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20%22No%20results%20returned%22%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%0A%20%20%20public%20function%20editEvent(%24id%2C%20%24event_name%2C%20%24description)%20%7B%0A%20%20%20%20%20%20%20%24event_name%20%3D%20filter_var(%24event_name%2C%20FILTER_SANITIZE_STRING)%3B%0A%20%20%20%20%20%20%20%24description%20%3D%20filter_var(%24description%2C%20FILTER_SANITIZE_STRING)%3B%0A%20%20%20%20%20%20%20%24id%20%3D%20filter_var(%24id%2C%20FILTER_SANITIZE_NUMBER_INT)%3B%0A%0A%20%20%20%20%20%20%20%24db%20%3D%20new%20DatabaseTranscations()%3B%0A%20%20%20%20%20%20%20%24result%20%3D%20%24db-%3Eupdate(%24event_name%2C%20%24description%2C%20%24id)%3B%0A%20%20%20%20%20%20%20if%20(%24result)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20true%3B%0A%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%0A%20%20%20public%20function%20deleteEvent(%24id)%20%7B%0A%20%20%20%20%20%20%20%24id%20%3D%20filter_var(%24id%2C%20FILTER_SANITIZE_NUMBER_INT)%3B%0A%20%20%20%20%20%20%20%24db%20%3D%20new%20DatabaseTranscations()%3B%0A%20%20%20%20%20%20%20%24result%20%3D%20%24db-%3Edelete(%24id)%3B%0A%20%20%20%20%20%20%20if%20(%24result)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20%22deleted%22%3B%0A%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20%22Something%20happened%20event%20not%20deleted%22%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%7D%0A%3F%3E%0A" message="" highlight="" provider="manual"/]Within this file, I have defined methods for creating, updating, viewing and deleting an event.

Templates

Landing page

This will be the index page. This page will display the events, and have a button for creating a new event.[pastacode lang="php" manual="%3C%3Fphp%0Arequire%20%22..%2Fmodels%2Fevent.php%22%3B%0A%3F%3E%0A%3Cbody%3E%0A%20%20%20%3C%3Fphp%20require%20%22app.php%22%3B%20%3F%3E%0A%20%20%20%3Cdiv%20class%3D%22jumbotron%22%3E%0A%20%20%20%20%20%20%20%3C%3Fphp%0A%20%20%20%20%20%20%20%24s%20%3D%20new%20Event()%3B%0A%20%20%20%20%20%20%20%24result%20%3D%20%24s-%3EviewEvents()%3B%0A%20%20%20%20%20%20%20foreach%20(%24result%20as%20%24row)%20%3A%0A%20%20%20%20%20%20%20%3F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22list-group%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Ca%20href%3D%22view.php%3Fid%3D%3C%3Fphp%20echo%20%24row%5B'id'%5D%3B%20%3F%3E%22%20class%3D%22list-group-item%20list-group-item-action%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%3Fphp%20echo%20%24row%5B'event_name'%5D%3B%20%3F%3E%20%3Cbr%20%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fa%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3C%2Fdiv%3E%0A%20%20%20%20%20%20%20%3C%3Fphp%20endforeach%3B%20%3F%3E%0A%20%20%20%3C%2Fdiv%3E%0A%3C%2Fbody%3E%0A" message="" highlight="" provider="manual"/]Below is what the landing page would look like. I have made use of bootstrap in this project. Check out this link for more on bootstrap.

events create view all

Each event item is clickable and when clicked, it should redirect to a page that shows the details of the event. To enable this, we pass theid of the event to the URL.[pastacode lang="php" manual="%3Ca%20href%3D%22view.php%3Fid%3D%3C%3Fphp%20echo%20%24row%5B'id'%5D%3B%20%3F%3E%22%20class%3D%22list-group-item%20list-group-item-action%22%3E%0A%0A%0A" message="" highlight="" provider="manual"/]

View details of a single event

We will create a page that will display the details of a single event. When an event is clicked, it will redirect to this page.

WP Content

[pastacode lang="php" manual="if%20(isset(%24_GET%5B'id'%5D))%20%7B%0A%20%20%20%20%20%20%20%24event%20%3D%20new%20Event()%3B%0A%20%20%20%20%20%20%20%24result%20%3D%20%24event-%3EviewEvent(%24_GET%5B'id'%5D)%3B%0A%20%20%20%7D%0A" message="" highlight="" provider="manual"/]The above line of code picks up the id which is passed in the URL and passes it along to the viewEvent method which then returns details of the selected event.The page also has edit and delete buttons. The edit button when clicked also passes the id of the event to the URL.[pastacode lang="css" manual="%3Cbutton%20class%3D%22card-link%20btn%20btn-primary%22%20onclick%3D%22window.location.href%20%3D%20'edit.php%3Fid%3D%3C%3Fphp%20echo%20%24result%5B'id'%5D%3B%20%3F%3E'%22%3EEdit%3C%2Fbutton%3E%0A%0A" message="" highlight="" provider="manual"/]The delete button loads a popup a modal which asks the user to confirm if they would like to delete the selected event. The pop up looks like this

navigation menu

[pastacode lang="php" manual="%3C%3Fphp%20require%20%22..%2Fmodels%2Fevent.php%22%3B%0Arequire%20%22app.php%22%3B%20%3F%3E%0A%0A%3Cbody%3E%0A%20%20%20%3C%3Fphp%0A%20%20%20if%20(isset(%24_GET%5B'id'%5D))%20%7B%0A%20%20%20%20%20%20%20%24event%20%3D%20new%20Event()%3B%0A%20%20%20%20%20%20%20%24result%20%3D%20%24event-%3EviewEvent(%24_GET%5B'id'%5D)%3B%0A%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20echo%20%22Something%20went%20wrong!%22%3B%0A%20%20%20%20%20%20%20exit%3B%0A%20%20%20%7D%20%3F%3E%0A%20%20%20%3Ch1%3EShowing%20details%20for%20%3C%3Fphp%20echo%20%24result%5B'event_name'%5D%3B%20%3F%3E%20%3C%2Fh1%3E%0A%20%20%20%3Cdiv%20class%3D%22jumbotron%20text-center%22%3E%0A%20%20%20%20%20%20%20%3Cp%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cstrong%3EEvent%3A%3C%2Fstrong%3E%20%3C%3Fphp%20echo%20%24result%5B'event_name'%5D%3B%20%3F%3E%3Cbr%3E%0A%0A%20%20%20%20%20%20%20%20%20%20%20%3Cstrong%3EDescription%3A%3C%2Fstrong%3E%20%3C%3Fphp%20echo%20%24result%5B'description'%5D%3B%20%3F%3E%3Cbr%3E%0A%20%20%20%20%20%20%20%3C%2Fp%3E%0A%20%20%20%20%20%20%20%3Cbutton%20class%3D%22btn%20btn-primary%22%20onclick%3D%22window.location.href%20%3D%20'edit.php%3Fid%3D%3C%3Fphp%20echo%20%24result%5B'id'%5D%3B%20%3F%3E'%22%3EEdit%3C%2Fbutton%3E%0A%20%20%20%20%20%20%20%3C!--%20Button%20trigger%20modal%20--%3E%0A%20%20%20%20%20%20%20%3Cbutton%20type%3D%22button%22%20class%3D%22btn%20btn-primary%22%20data-toggle%3D%22modal%22%20data-target%3D%22%23exampleModalCenter%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20Delete%0A%20%20%20%20%20%20%20%3C%2Fbutton%3E%0A%20%20%20%3C%2Fdiv%3E%0A%20%20%20%3C!--%20Modal%20--%3E%0A%20%20%20%3Cdiv%20class%3D%22modal%20fade%22%20id%3D%22exampleModalCenter%22%20tabindex%3D%22-1%22%20role%3D%22dialog%22%20aria-labelledby%3D%22exampleModalCenterTitle%22%20aria-hidden%3D%22true%22%3E%0A%20%20%20%20%20%20%20%3Cdiv%20class%3D%22modal-dialog%20modal-dialog-centered%22%20role%3D%22document%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22modal-content%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22modal-header%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Ch5%20class%3D%22modal-title%22%20id%3D%22exampleModalLongTitle%22%3EDelete%20event%3C%2Fh5%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cbutton%20type%3D%22button%22%20class%3D%22close%22%20data-dismiss%3D%22modal%22%20aria-label%3D%22Close%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cspan%20aria-hidden%3D%22true%22%3E%26times%3B%3C%2Fspan%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fbutton%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fdiv%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22modal-body%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Are%20you%20sure%20you%20want%20to%20delete%20the%20event%20%3C%3Fphp%20echo%20%24result%5B'event_name'%5D%3B%20%3F%3E%3F%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fdiv%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cdiv%20class%3D%22modal-footer%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cbutton%20type%3D%22button%22%20class%3D%22btn%20btn-secondary%22%20data-dismiss%3D%22modal%22%3ENo%3C%2Fbutton%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cbutton%20onclick%3D%22window.location.href%20%3D%20'delete.php%3Fid%3D%3C%3Fphp%20echo%20%24result%5B'id'%5D%3B%20%3F%3E'%22%20class%3D%22btn%20btn-primary%22%3EYes%3C%2Fbutton%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fdiv%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3C%2Fdiv%3E%0A%20%20%20%20%20%20%20%3C%2Fdiv%3E%0A%20%20%20%3C%2Fdiv%3E%0A%20%20%0A%3C%2Fbody%3E%0A" message="" highlight="" provider="manual"/]

Create and Edit an event

The landing page has a link that allows a user to add an event. When clicked, the user is redirected to a page that loads a form so a user can enter details of the event to be created.

web form

The user fills in the details in the form above when done, they hit the submit button, which submits the data.[pastacode lang="php" manual="%3C%3Fphp%0Arequire%20%22..%2Fmodels%2Fevent.php%22%3B%0Asession_start()%3B%0Aif%20(!isset(%24_SESSION%5B'count'%5D))%20%7B%0A%20%20%20%24_SESSION%5B'count'%5D%20%3D%200%3B%0A%7D%20else%20%7B%0A%20%20%20%24_SESSION%5B'count'%5D%2B%2B%3B%0A%7D%0Aif%20(isset(%24_POST%5B'submit'%5D))%20%7B%0A%20%20%20%24event_name%20%3D%20%24_POST%5B'eventName'%5D%3B%0A%20%20%20%24description%20%3D%20%24_POST%5B'description'%5D%3B%0A%20%20%20%24insert%20%3D%20new%20Event()%3B%0A%20%20%20%24insert-%3EaddEvent(%24event_name%2C%20%24description)%3B%0A%20%20%20%24_SESSION%5B%22flash%22%5D%20%3D%20%5B%22type%22%20%3D%3E%20%22success%22%2C%20%22message%22%20%3D%3E%20%22Event%20successfully%20created%22%5D%3B%0A%20%20%20header(%22Location%3A%22%20.%20%22index.php%22)%3B%0A%7D%0A%3F%3E%0A" message="" highlight="" provider="manual"/]This section of the code runs after the form is submitted. The $_POST is a super PHP global variable that is used to collect form data.[pastacode lang="php" manual="%3Cinput%20name%3D%22eventName%22%20type%3D%22text%22%20class%3D%22form-control%22%20id%3D%22eventName%22%20placeholder%3D%22Enter%20event%20name%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cinput%20name%3D%22description%22%20type%3D%22text%22%20class%3D%22form-control%22%20id%3D%22description%22%20placeholder%3D%22Enter%20a%20description%20for%20your%20event%22%3E%0A" message="" highlight="" provider="manual"/]As you can see the input elements have a name attribute, this attribute becomes the key of the associative $_POST array with the form input value becoming the value.As you can see, once the entered values are picked from the array, they are passed to the addEvent method which then handles the data insert.The edit works more or less the same as the create except that in the case of edit, the form is pre-populated.

Delete

When a user selects Yes from the modal that pops up when the delete button is clicked.

navigation menu>The id of the event is passed to the URL and <strong><em><span style=

delete.php is called where the id is picked from the URL and passed to the method deleteEvent which handles the delete. Upon delete, the user is redirected to the landing page where a success message is displayed.

events create view all

This is achieved through the use of PHP's super global variable $_SESSION. We add the message to be displayed to the session.[pastacode lang="php" manual="%20%24_SESSION%5B%22delete%22%5D%20%3D%20%5B%22type%22%20%3D%3E%20%22danger%22%2C%20%22message%22%20%3D%3E%20%22Event%20successfully%20deleted%22%5D%3B" message="" highlight="" provider="manual"/]The above line of code is setting the message to display in the PHP $_SESSION global variable.We then pick this message from the session variable and display on the landing page[pastacode lang="php" manual="if%20(isset(%24_SESSION%5B%22flash%22%5D))%20%7B%0A%20%20%20%20%20%20%20vprintf(%22%3Cp%20class%3D'flash%20%25s%20btn%20btn-success'%3E%25s%3C%2Fp%3E%22%2C%20%24_SESSION%5B%22flash%22%5D)%3B%0A%20%20%20%20%20%20%20unset(%24_SESSION%5B%22flash%22%5D)%3B%0A%20%20%20%7D%0A%0A%20%20%20elseif%20(isset(%24_SESSION%5B%22delete%22%5D))%20%7B%0A%20%20%20%20%20%20%20vprintf(%22%3Cp%20class%3D'flash%20%25s%20btn%20btn-danger'%3E%25s%3C%2Fp%3E%22%2C%20%24_SESSION%5B%22delete%22%5D)%3B%0A%20%20%20%20%20%20%20unset(%24_SESSION%5B%22delete%22%5D)%3B%0A%20%20%20%7D%0A" message="" highlight="" provider="manual"/]The above code handles the display of the flash messages from the session variable.

Conclusion

And that marks the end of our very simple CRUD application in vanilla PHP without using any framework. I hope it has been helpful. If you have any comments or questions please do feel free to ask.

Related posts

The latest articles from Andela.

Visit our blog

Overcoming the Challenges of Working With a Mobile FinTech API

Andela community member Zzwia Raymond explores why, despite the potential of the MTN Mobile Money platform and its API, there are technical hurdles, from complex documentation to enhancing functionality.

How Andela Transformed Tech Hiring in 10 Years

Celebrating 10 years of transforming tech hiring by unlocking global talent across Africa, Latin America and beyond, Andela has surpassed its original goal by training nearly 110,000 technologists and assembling one of the world's largest remote tech talent marketplaces.

What GPT-4o and Gemini releases mean for AI

The latest generative AI models from OpenAI (GPT-4) and Google (Gemini 1.5 Pro, Veo, etc.) promise improved capabilities, lower costs, and transformative applications across various industries by integrating advanced AI technologies into business operations.

We have a 96%+
talent match success rate.

The Andela Talent Operating Platform provides transparency to talent profiles and assessment before hiring. AI-driven algorithms match the right talent for the job.