Commit 40039976 authored by Sorrel Harriet's avatar Sorrel Harriet
Browse files

adding lab 7 files

parent ae6c9c82
Live Demo
---------
A live deployment of this app can be viewed at:
http://doc.gold.ac.uk/~sharr003/dnw/lab-6/music-store-app/
Configuration
-------------
- Create a blank MySQL database
- Run the statements in sql/schema.sql on your MySQL database to set up the app schema
- Run the statements in sql/dummy-data.sql on your MySQL database to insert some dummy data (optional)- Edit includes/db_connect.php with your database connection details
<?php
// define a connection 'handle'
$link = mysqli_connect(
'localhost',
'sorrel',
'password123',
'musicstore'
);
// check connection succeeded
if (mysqli_connect_errno()) {
exit(mysqli_connect_error());
}
?>
<?php
// include the HTML for the page header
include "templates/header.html";
// include the HTML for the navigation bar
include "templates/nav.html";
// open a new MySQL database connection
require "includes/db_connect.php";
// check if 'page' parameter is set in query string
if (isset($_GET['page'])) {
$page = $_GET['page']; // if so, set page variable to value of 'page' parameter
} else {
$page = 'home'; // if not, set page variable to home
}
// define a variable to store content HTML
$content = "";
// determine which view to serve based on value of $page
switch ($page) {
case 'home' :
include 'views/home.php';
break;
case 'albums' :
include 'views/albums.php';
break;
case 'album' :
include 'views/album.php';
break;
case 'add-track' :
include 'views/add-track.php';
break;
default :
include 'views/404.php';
}
// close the connection to the database */
mysqli_close($link);
// output the HTML
echo $content;
//
include "templates/footer.html";
?>
INSERT INTO Genre (name)
VALUES
('Reggae'),
('Funk and Soul'),
('Jazz'),
('Classical'),
('Electronic'),
('Pop');
INSERT INTO Band (name, genre_id)
VALUES
('The Wailers', 1),
('The Aces', 2),
('The Beatles', 6);
INSERT INTO Artist (first_name, last_name, band_id)
VALUES
('Bob', 'Marley', 1),
('Peter', 'Tosh', 1),
('Burning', 'Spear', NULL),
('Alton', 'Ellis', NULL),
('Gregory', 'Issacs', NULL),
('Desmond', 'Dekker', 2),
('John', 'Lennon', 3),
('Madonna', NULL, NULL);
INSERT INTO Album (upc, title, release_year, artist_id, compilation, price, genre_id)
VALUES
('123425364732', 'Soul Rebel', 1970, 1, FALSE, 25.99, 1 ),
('017263547261', 'Catch A Fire', 1973, 1, 0, 25.99, 1 ),
('018263526272', 'Natty Dread', 1974, 1, 1, 20.99, 1 ),
('018273527273', 'Babylon By Bus', 1978, 1, 'FALSE', 24.99, 1 ),
('491827364626', 'Night Nurse', 1982, 5, TRUE, 17.99, 1 ),
('018276272828', 'Mr Issacs', 1982, 5, 0, 9.99, 1 ),
('018273662728', 'Black and Dekker', 1980, 6, 0, 19.99, 1 ),
('726517237627', 'Sunday Coming', 1970, 4, TRUE, 15.99, 1 ),
('018274372722', 'Imagine', 1971, 7, NULL, 11.99, 6 ),
('018273727287', 'Like a Virgin', 1984, 8, 1, 9.99, 6 );
INSERT INTO Track (name, album_upc, track_number)
VALUES
('Sunday Coming', '726517237627', 1),
('Imagine', '018274372722', 1),
('Material Girl', '018273727287', 1),
('Angel', '018273727287', 2),
('Crippled Inside', '018274372722', 2),
('These Eyes', '726517237627', 2),
('Hurting Me', '726517237627', 3);
INSERT INTO Customer (username, email_address, password, first_name, last_name, address_1, address_2, postcode)
VALUES
('sharr003', 's.harriet@gold.ac.uk', 'SOME_HASHED_VALUE', 'Sorrel', 'Harriet', '12 Fake Street', 'London', 'SE140PL'),
('ktack001', 'k.tackie@hotmail.com', 'SOME_HASHED_VALUE', 'Kobi', 'Tackie', '12 Fake Street', 'London', 'SE140PL');
INSERT INTO Transaction (customer_id, delivery)
VALUES
(1, 'next working day'),
(1, 'first class'),
(2, 'second class');
INSERT INTO LineItem (trans_id, album_upc, quantity)
VALUES
(1, '018273727287', 1),
(2, '018273727287', 1),
(3, '491827364626', 1),
(1, '018274372722', 2);
/* Minimum functional requirements of
Music Store App and their associated queries.
Where variations are given they are
given in order of increasing complexity */
/* 1a. Retrieve a list of Albums
Include the UPC, title, price, artist name
and genre in the result-set.
Order by title (a-z) */
SELECT Album.title, Album.price, Artist.first_name, Artist.last_name, Genre.name AS genre
FROM Album /* notice the use of a column alias! */
INNER JOIN Artist
ON Album.artist_id=Artist.id
INNER JOIN Genre
ON Album.genre_id=Genre.id
ORDER BY title ASC; /* causes results to be ordered by album title */
/* 1b. Retrieve a list of Albums
Include the UPC, title, price, artist name,
genre, and number of tracks in the result-set.
Include only albums which have tracks in DB.
Order by title (a-z) */
SELECT Album.title, Album.price, Artist.first_name, Artist.last_name, Genre.name AS genre, (SELECT COUNT(*) FROM Track WHERE Album.upc=Track.album_upc) AS num_tracks
FROM Album /* notice the nested query, aggregate function and aliases! */
INNER JOIN Track
ON Album.upc=Track.album_upc
INNER JOIN Artist
ON Album.artist_id=Artist.id
INNER JOIN Genre
ON Album.genre_id=Genre.id
GROUP BY title /* group by album title to avoid duplicate rows */
ORDER BY title ASC;
/* 1c. Retrieve a list of Albums
Include the UPC, title, price, artist name,
genre, and number of tracks in the result-set.
Include ALL albums, even those without tracks.
Order by title (a-z) */
SELECT Album.title, Album.price, Artist.first_name, Artist.last_name, Genre.name AS genre, (SELECT COUNT(*) FROM Track WHERE Album.upc=Track.album_upc) AS num_tracks
FROM Album /* notice the nested query, aggregate function and aliases! */
INNER JOIN Artist
ON Album.artist_id=Artist.id
INNER JOIN Genre
ON Album.genre_id=Genre.id
ORDER BY title ASC;
/* ------------------------------------ */
/* 2. Retrieve a list of tracks
associated with a specific album */
SELECT t.name AS track, t.track_number, a.title AS album /* notice use of column aliases! */
FROM Track t /* notice use of table aliases! */
INNER JOIN Album a
ON t.album_upc=a.upc
WHERE a.upc='018274372722' /* EXAMPLE */
ORDER BY track_number ASC;
/* ------------------------------------ */
/* 3. Insert a new track */
INSERT INTO Track (name, album_upc, track_number)
VALUES
('Sunday Coming', '726517237627', 1); /* EXAMPLE */
/* ------------------------------------ */
/* 4. Delete a track */
DELETE FROM Track WHERE album_upc='726517237627'; /* EXAMPLE */
/* ------------------------------------ */
/* 5a. Retrieve details about an order
Include the customer_id, delivery method
and total order value in the result-set */
SELECT Transaction.customer_id, Transaction.delivery, SUM(Album.price*LineItem.quantity) AS order_total /* notice use of aggregate function! */
FROM Transaction
INNER JOIN LineItem
ON Transaction.id=LineItem.trans_id
INNER JOIN Album
ON Album.upc=LineItem.album_upc
WHERE Transaction.id=1; /* EXAMPLE */
/* 5b. Retrieve details about an order
Include the transaction id, customer_id
and the number of items ordered in the
result-set */
SELECT t.id, t.customer_id, SUM(li.quantity) AS num_items
FROM Transaction t
INNER JOIN LineItem li
ON t.id=li.trans_id
GROUP BY t.id; /* group results by transaction id */
/* 5c. Does the same as the previous query
but using a nested query rather than a JOIN */
SELECT t.id, t.customer_id,
(SELECT SUM(li.quantity) FROM LineItem li
WHERE li.trans_id=t.id) AS num_items
FROM Transaction t;
/* Delete existing tables in reverse order of creation
so as not to violate any foreign key constraints */
DROP TABLE IF EXISTS Rating, Wish, LineItem, Transaction, Customer, Track, Album, Artist, Band, Genre;
/* Define table for genres */
CREATE TABLE Genre (
id INT AUTO_INCREMENT,
name VARCHAR(25) UNIQUE NOT NULL,
PRIMARY KEY (id)
);
/* Define table for storing act (i.e. a group or solo artist)
ON DELETE CASCADE not used in this case as we don't want bands
being deleted if their genre is deleted. We'd rather an error
was raised. */
CREATE TABLE Band (
id INT AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
genre_id INT,
PRIMARY KEY (id),
FOREIGN KEY (genre_id)
REFERENCES Genre (id)
);
/* Define table for storing artists */
CREATE TABLE Artist (
id INT AUTO_INCREMENT,
first_name VARCHAR(25) NOT NULL,
last_name VARCHAR(25),
band_id INT,
PRIMARY KEY (id),
FOREIGN KEY (band_id)
REFERENCES Band (id)
);
/* Define table for storing albums */
CREATE TABLE Album (
upc CHAR(12),
title VARCHAR(50) NOT NULL,
release_year YEAR(4),
artist_id INT,
compilation BOOLEAN NOT NULL DEFAULT 0,
price DECIMAL(5, 2) unsigned NOT NULL,
genre_id INT,
PRIMARY KEY (upc),
FOREIGN KEY (artist_id)
REFERENCES Artist (id),
FOREIGN KEY (genre_id)
REFERENCES Genre (id)
);
/* Define table for storing single tracks
ON DELETE CASCADE will ensure no track
is left that isn't linked to an album.
ON UPDATE CASCADE will inherit any changes
to the Album UPC (Universal Product Code).
A composite PRIMARY KEY is used here to
ensure the track_number is unique
on any given album */
CREATE TABLE Track (
name VARCHAR(50) NOT NULL UNIQUE,
album_upc CHAR(12) NOT NULL,
track_number INT,
PRIMARY KEY (album_upc, track_number),
FOREIGN KEY (album_upc)
REFERENCES Album (upc)
ON UPDATE CASCADE
ON DELETE CASCADE
);
/* Define table for storing customers */
CREATE TABLE Customer (
id INT AUTO_INCREMENT,
username VARCHAR(25) UNIQUE NOT NULL,
email_address VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(64), /* will store a hashed password */
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
address_1 VARCHAR(50) NOT NULL,
address_2 VARCHAR(50),
postcode VARCHAR(10) NOT NULL,
PRIMARY KEY (id)
);
/* Define table for storing orders */
CREATE TABLE Transaction (
id INT AUTO_INCREMENT,
customer_id INT NOT NULL,
delivery ENUM('first class','second class','next working day'),
PRIMARY KEY (id),
FOREIGN KEY (customer_id)
REFERENCES Customer(id)
ON DELETE CASCADE
);
/* Define table for storing line items */
CREATE TABLE LineItem (
id INT AUTO_INCREMENT,
trans_id INT NOT NULL,
album_upc CHAR(12) NOT NULL,
quantity INT NOT NULL DEFAULT 1,
PRIMARY KEY (id),
FOREIGN KEY (trans_id)
REFERENCES Transaction (id)
ON DELETE CASCADE,
FOREIGN KEY (album_upc)
REFERENCES Album (upc)
ON DELETE CASCADE
);
/* Define table to store customer 'wishes'.
Compile wishlists from this data. */
CREATE TABLE Wish (
customer_id INT,
album_upc CHAR(12) NOT NULL,
PRIMARY KEY (customer_id, album_upc),
FOREIGN KEY (customer_id)
REFERENCES Customer(id)
ON DELETE CASCADE,
FOREIGN KEY (album_upc)
REFERENCES Album (upc)
ON DELETE CASCADE
);
/* Define table for storing customer ratingsfor albums */
CREATE TABLE Rating (
customer_id INT NOT NULL,
album_upc CHAR(12) NOT NULL,
score TINYINT unsigned NOT NULL,
PRIMARY KEY (customer_id, album_upc),
FOREIGN KEY (customer_id)
REFERENCES Customer(id)
ON DELETE CASCADE,
FOREIGN KEY (album_upc)
REFERENCES Album (upc)
ON DELETE CASCADE
);
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'/>
<title>Music Store: {{ page }}</title>
</head>
<body>
<nav>
<ul>
<li><a href='index.php?page=home'>Home</a></li>
<li><a href='index.php?page=albums'>Albums</a></li>
<li><a href='index.php?page=add-track'>Add Track</a></li>
</ul>
</nav>
<?php
$content = "<h1>Add a track</h1>";
// define a variable with path to the script which will process form
// -> $_SERVER["PHP_SELF"] is a path to the current script (index.php)
$action = $_SERVER["PHP_SELF"]."?page=add-track";
// fetch the albums so that we have access to their names and prices
$sql = "SELECT upc, title
FROM Album
ORDER BY title";
$result = mysqli_query($link, $sql);
// check query returned a result
if ($result === false) {
echo mysqli_error($link);
} else {
$options = "";
// create an option for each artist
while ($row = mysqli_fetch_assoc($result)) {
$options .= "<option value='".$row['upc']."'>";
$options .= $row['title'];
$options .= "</option>";
}
}
// define the form HTML (would ideally be in a template)
$form_html = "<form action='".$action."' method='POST'>
<fieldset>
<label for='t_name'>Name:</label>
<input type='text' name='t_name' required>
</fieldset>
<fieldset>
<label for='t_number'>Track number:</label>
<input type='text' name='t_number'>
</fieldset>
<fieldset>
<label for='a_upc'>Album:</label>
<select name='a_upc' required>
<option value='' disabled selected>Select an album</option>
".$options."
</select>
</fieldset>
<button type='submit'>Submit</button>
</form>";
// append form HTML to content string
$content .= $form_html;
// ------- START form processing code... -------
// define variables and set to empty values
$t_name = $a_upc = $t_number = "";
// check if there was a POST request
if ($_SERVER["REQUEST_METHOD"] == "POST") {
// validate the form data
$a_upc = $_POST["a_upc"];
$t_name = $_POST["t_name"];
$t_number = $_POST["t_number"];
// define the insertion query
$sql = "INSERT INTO Track (album_upc, name, track_number)
VALUES ('$a_upc', '$t_name', '$t_number')";
// run the query to insert the data
$result = mysqli_query($link, $sql);
// check if the query went ok
if ($result === false) {
// if not, output mysql error message
echo mysqli_error($link);
} else {
$content .= "Track successfully added.";
}
}
// ------- END form processing code... -------
?>
<?php
$content = "<h1>Add a track</h1>";
// define a variable with path to the script which will process form
// -> $_SERVER["PHP_SELF"] is a path to the current script (index.php)
$action = $_SERVER["PHP_SELF"]."?page=add-track";
// fetch the albums so that we have access to their names and prices
$sql = "SELECT upc, title
FROM Album
ORDER BY title";
$result = mysqli_query($link, $sql);
// check query returned a result
if ($result === false) {
echo mysqli_error($link);
} else {
$options = "";
// create an option for each artist
while ($row = mysqli_fetch_assoc($result)) {
$options .= "<option value='".$row['upc']."'>";
$options .= $row['title'];
$options .= "</option>";
}
}
// define the form HTML (would ideally be in a template)
$form_html = "<form action='".$action."' method='POST'>
<fieldset>
<label for='t_name'>Name:</label>
<input type='text' name='t_name' required>
</fieldset>
<fieldset>
<label for='t_number'>Track number:</label>
<input type='number' name='t_number' min='1' max='25'>
</fieldset>
<fieldset>
<label for='a_upc'>Album:</label>
<select name='a_upc' required>
<option value='' disabled selected>Select an album</option>
".$options."
</select>
</fieldset>
<button type='submit'>Submit</button>
</form>";
// append form HTML to content string
$content .= $form_html;
// ------- START form processing code... -------
// define a function to sanitise user input (this would ideally be in includes folder)
// helps protect against XSS
function clean_input($data) {
$data = trim($data); // strips unnecessary characters from beginning/end
$data = stripslashes($data); // remove backslashes
$data = htmlspecialchars($data); // replace special characters with HTML entities
return $data;
}
// define variables and set to empty values
$title = $artist_id = $price = $year = $genre = "";
// check if there was a POST request
if ($_SERVER["REQUEST_METHOD"] == "POST") {
// validate the form data
$a_upc = mysqli_real_escape_string($link, clean_input($_POST["a_upc"]));
$t_name = mysqli_real_escape_string($link, clean_input($_POST["t_name"]));
$t_number = mysqli_real_escape_string($link, clean_input($_POST["t_number"]));
// define the insertion query
$sql = sprintf("INSERT INTO Track (album_upc, name, track_number)
VALUES ('%s', '%s', %d)", $a_upc, $t_name, $t_number);
// run the query to insert the data
$result = mysqli_query($link, $sql);
// check if the query went ok
if ($result === false) {
// handle specific errors based on mysli error number code
// (in order to output more useful message to user!)
$errno = mysqli_errno($link);
switch ($errno) {
case 1062 : // case for duplicate entry
$content .= "There is already a track with that name or number.";
break;
default :
echo mysqli_error($link);
}
} else {
$content .= "Track successfully added.";
}
}
// ------- END form processing code... -------
?>
<?php
// define the SQL query to run (from lab 3 queries.sql!)
// use column aliases if necessary to make referencing fields in result-set easier
$sql = "SELECT Album.title, Album.price, Album.upc, Artist.first_name, Artist.last_name, Genre.name AS genre, (SELECT COUNT(*) FROM Track WHERE Album.upc=Track.album_upc) AS num_tracks
FROM Album
INNER JOIN Artist
ON Album.artist_id=Artist.id
INNER JOIN Genre
ON Album.genre_id=Genre.id
ORDER BY title ASC;";