Host Database App

Code


host-simple-db
├── api
│   └── v1
│       └── index.php
├── database
│   ├── config.php
│   ├── database.php
│   ├── schema.mwb
│   └── schema.sql
├── install
│   └── index.php
├── model
│   └── host.php
└── public
    ├── css
    │   └── master.css
    ├── index.html
    └── js
        └── main.js

Install


http://localhost:8080/install/:

<?php

require_once(__DIR__ . '/../database/config.php');

try {
  $schema = file_get_contents('../database/schema.sql');
  $connection = new PDO(DB . ":host=" . DBHOST, DBUSER, DBPWD);
  $connection->exec($schema);
  // echo "Database installed!";
  header('Location: /public/');;
} catch (PDOException $e) {
  echo 'Connection failed: ' . $e->getMessage();
}

database/config.php:

<?php

const DB = 'mysql';
const DBHOST = 'mysql';
const DBNAME = 'computer';
const DBUSER = 'root';
const DBPWD = 'secret';

Back-end side


Code:

host-simple-db
├── api
│   └── v1
│       └── index.php
├── database
│   ├── config.php
│   ├── database.php
│   └── schema.sql
├── install
│   └── index.php
└── model
    └── host.php

Front-end side


host-simple-db
└── public
    ├── css
    │   └── master.css
    ├── index.html
    └── js
        └── main.js

public/index.html:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.2.0/css/all.css" integrity="sha384-hWVjflwFxL6sNzntih27bfxkr27PmbbK/iSvJ+a4+0owXq79v+lsFkW54bOGbiDQ" crossorigin="anonymous">
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
    <link rel="stylesheet" href="css/master.css">

    <title>Host App</title>
  </head>
  <body>
    <header>
      <h1>Host App</h1>
    </header>
    <main class="container">
      <div class="row justify-content-center">
        <div class="col-8">
          <form class="mb-4">
            <div class="row">
              <div class="col-5">
                <input type="text" name="name" class="form-control" placeholder="Hostname">
              </div>
              <div class="col-5">
                <input type="text" name="address" class="form-control" placeholder="IP Address">
              </div>
              <div class="col-2">
                <button class="btn btn-light">Create</button>
              </div>
            </div>
          </form>
        </div>
      </div>
      <table id="hosts" class="table">
        <thead>
          <th></th>
          <th>Name</th>
          <th>Address</th>
          <th></th>
        </thead>
        <tbody>

        </tbody>
      </table>
    </main>

    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
    <script src="js/main.js"></script>
  </body>
</html>

public/css/master.css:

body {
  margin: 0;
  font-family: Arial, Helvetica, sans-serif;
}

header {
  padding: .2rem 0;
  text-align: center;
  background: #fafafa;
  border-bottom: 1px solid #ccc;
  margin-bottom: 3rem;
}

table {
  counter-reset: row;
}

table .count::before {
  counter-increment: row;
  content: counter(row);
}

table .edit,
table .remove {
  color: #ccc;
  margin-left: 1rem;
}

table .edit:hover,
table .remove:hover {
  color: #000;
}

public/js/main.js:

const hostTable = document.querySelector('#hosts')
const createHostForm = document.querySelector('form')

loadHosts()
createHostForm.onsubmit = createHostEvent

function loadHosts() {
  fetch('../api/v1/')
    .then(res => res.json())
    .then(json => drawHosts(json))
}

function drawHosts(hosts) {
  for (const host of hosts) {
    createHostRow(host)
  }
}

function createHostRow(host) {
  hostTable.insertAdjacentHTML('beforeend', getHostRow(host))
  hostTable.lastChild.querySelector('.edit').onclick = editHostEvent
  hostTable.lastChild.querySelector('.remove').onclick = removeHostEvent
}

function getHostRow(host) {
  return `<tr data-host-id="${host.id}">
      <td class="count"></td>
      <td class="name">${host.name}</td>
      <td class="address">${host.address}</td>
      <td>
        <i class="fas fa-pencil-alt edit"></i>
        <i class="fas fa-times remove"></i>
      </td>
    </tr>`
}

// Events
function createHostEvent(event) {
  event.preventDefault()

  const formData = new FormData(createHostForm)
  const name = formData.get('name')
  const address = formData.get('address')

  fetch(`../api/v1/?a=readOrCreate&name=${name}&address=${address}`)
    .then(res => res.json())
    .then(host => createHostRow(host))
  createHostForm.reset()
}

function removeHostEvent(event) {
  const row = event.target.parentNode.parentNode
  const hostId = row.dataset.hostId
  fetch(`../api/v1/?a=remove&id=${hostId}`)
  row.remove()
}

function updateHostEvent(event) {
  const row = event.target.parentNode.parentNode
  if (event.key === 'Enter') {
    const hostId = row.dataset.hostId
    const name = row.querySelector('.name')
    const address = row.querySelector('.address')

    const nameValue = name.firstChild.value
    const addressValue = address.firstChild.value
    fetch(`../api/v1/?a=update&id=${hostId}&name=${nameValue}&address=${addressValue}`)

    name.innerHTML = nameValue
    address.innerHTML = addressValue
  }
}

function editHostEvent(event) {
  const row = event.target.parentNode.parentNode

  const name = row.querySelector('.name')
  name.innerHTML = `<input type="text" value="${name.innerHTML}">`
  name.onkeyup = updateHostEvent

  const address = row.querySelector('.address')
  address.innerHTML = `<input type="text" value="${address.innerHTML}">`
  address.onkeyup = updateHostEvent
}