Session 14 - Server-Side, Part 2

Harvard Extension School  
Fall 2022

Course Web Site: https://cscie12.dce.harvard.edu/

Topics

  1. Announcements
  2. "Back end" (Server-Side) Web Development
  3. Server Side Rendering of Content (SSR)
  4. PHP Example with Courses Database
  5. Separation of Concerns
  6. {{Mustache}} Templates
  7. Improving the Hello! Greeting
  8. CSR (Client Side Rendering)
  9. JavaScript Frameworks - Vue, React, Angular, Ember
  10. Sending Email
  11. Oh, The Places You'll Go!
  12. Thank You!

Session 14 - Server-Side, Part 2, slide1
Announcements, slide2
Final Project Notes and Observations, slide3
"Back end" (Server-Side) Web Development, slide4
CSR or SSR or SSG, slide5
Server Side Rendering of Content (SSR), slide6
Web Program Examples, slide7
A Personal Greeting, slide8
A Personal Greeting, slide9
PHP Example with Courses Database, slide10
Harvard Extension Course Data, slide11
Data Table in a Relational Database, slide12
PHP Script to Connect to Database and Get List of Departments, slide13
Turn this into HTML Output, slide14
The entire "departments-simple.php", slide15
Adding another view - Department Course Listings, slide16
courses.php, slide17
Separation of Concerns, slide18
{{Mustache}} Templates, slide19
Mustache Departments, slide20
Mustache Courses, slide21
Improving the Hello! Greeting, slide22
Hello! Greeting, Improved, slide23
CSR (Client Side Rendering), slide24
JSON PHP data, slide25
Front-end courses, slide26
JavaScript Frameworks - Vue, React, Angular, Ember, slide27
CSCI E-12 Resources, slide28
Sending Email, slide29
Approaches to eCommerce, slide30
Oh, The Places You'll Go!, slide31
Thank You!, slide32

Presentation contains 32 slides

Announcements

Final Project Notes and Observations

"Back end" (Server-Side) Web Development

LanguageFrameworks/Platforms
JavaScript "Back-end": Node, Express
"Front-end": React, Vue, Angular, Ember
PHPLaravel, Symfony, CodeIgniter, CakePHP
CMS: WordPress, Drupal, Joomla, Concrete5, GetSimple
PythonDjango, Flask, Zope, Plone
Go

CSR or SSR or SSG

Server Side Rendering of Content (SSR)

Web Program Examples

Markup or content is embedded within a program; program embedded into markup

first.py - Python

first.py

#!/usr/bin/python3
print("Content-type: text/html\n\n")
print("<html><head><title>Hello World!</title></head>")
print("<body><h1>Hello, World!</h1></body></html>")

first.php - PHP

first.php

<?php
echo('<html><head><title>First PHP</title></head><body>');
echo('<h1>Hello!</h1>');
echo('</body></html>');
?>

second.php - PHP

second.php
program statements within markup

<?php
      $title = "Hello World!";
?>
<!DOCTYPE html>
  <head>
    <meta charset="utf-8" />
    <title><?php echo($title) ?></title>
  </head>
  <body>
    <h1><?php echo($title) ?></h1>
  </body>
</html>

A Personal Greeting

<?php
      $name = $_GET["name"];
?>
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Greeting Page</title>
  </head>
  <body>
    <h1>Hello, <?php echo($name) ?>!</h1>
  </body>
</html>

A Personal Greeting

Without a "name", present the user a form. With a name, provide a greeting.

<?php
      $name = $_GET["name"];
?>
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"/>
    <title>Greeting Page</title>
  </head>
  <body>
    <?php
    if ($name) {
      echo("<h1>Hello, $name!</h1>");
    } else {
      echo('<h1><label for="input_name">Enter name:</label></h1>');
      echo('<form method="get">');
      echo('<input type="text" name="name" id="input_name"/>');
      echo('<br /><input type="submit" />');
      echo('<br /><input type="reset" />');
    }
?>
  </body>
</html>
    

PHP Example with Courses Database

courses

courses

Harvard Extension Course Data

Course Data in a Spreadsheet

course data loaded in a spreadsheet

Data Table in a Relational Database

RDBMS = Relational Database Management System

Course Data in RDBMS Table

Course data for Faculty of Arts & Sciences is in a mysql database on cscie12students (username: class; database name: coursecatalog)

SQL:

describe ext_courses

Terminal:

cscie12students$ mysql -u class coursecatalog
Welcome to the MySQL monitor.  Commands end with ; or \g.

mysql> describe ext_courses;
+----------------------+--------------+------+-----+---------+-------+
| Field                | Type         | Null | Key | Default | Extra |
+----------------------+--------------+------+-----+---------+-------+
| academic_year        | year         | YES  |     | NULL    |       |
| term                 | varchar(32)  | YES  |     | NULL    |       |
| term_code            | int          | YES  |     | NULL    |       |
| course_code          | int          | YES  |     | NULL    |       |
| course_number        | int          | YES  |     | NULL    |       |
| short_title          | text         | YES  |     | NULL    |       |
| title                | text         | YES  |     | NULL    |       |
| faculty_description  | text         | YES  |     | NULL    |       |
| department_code      | varchar(15)  | YES  |     | NULL    |       |
| department           | varchar(200) | YES  |     | NULL    |       |
| course_type          | varchar(100) | YES  |     | NULL    |       |
| credits              | varchar(50)  | YES  |     | NULL    |       |
| credit_undergraduate | int          | YES  |     | NULL    |       |
| credit_graduate      | int          | YES  |     | NULL    |       |
| url                  | varchar(300) | YES  |     | NULL    |       |
| days_of_week         | varchar(100) | YES  |     | NULL    |       |
| start_time           | varchar(15)  | YES  |     | NULL    |       |
| end_time             | varchar(15)  | YES  |     | NULL    |       |
| location             | varchar(64)  | YES  |     | NULL    |       |
| notes                | text         | YES  |     | NULL    |       |
| description          | text         | YES  |     | NULL    |       |
+----------------------+--------------+------+-----+---------+-------+
21 rows in set (0.00 sec)

Selecting List of Departments

SQL Input:

select DISTINCT department_code, department from ext_courses

Terminal Output:

mysql> SELECT DISTINCT department_code, department FROM ext_courses ORDER BY department;
+-----------------+--------------------------------------+
| department_code | department                           |
+-----------------+--------------------------------------+
| AAAS            | African and African American Studies |
| ANTH            | Anthropology and Archaeology         |
| APMA            | Applied Mathematics                  |
| ARAB            | Arabic                               |
| ASTR            | Astronomy                            |
| BIOS            | Biological Sciences                  |
| BIOT            | Biotechnology                        |
| CELT            | Celtic Languages and Literatures     |
| CHEM            | Chemistry                            |
| CLAS            | Classics                             |
| CSCI            | Computer Science                     |
| CREA            | Creative Writing                     |
| DEVP            | Development Practice                 |
| DGMD            | Digital Media                        |
| DRAM            | Dramatic Arts                        |
| ECON            | Economics                            |
| EDUC            | Education                            |
| ENSC            | Engineering Sciences                 |
| ENGL            | English                              |
| ENVR            | Environmental Studies                |
| EXPO            | Expository Writing                   |
| FREN            | French Language and Literature       |
| GERM            | German                               |
| GOVT            | Government                           |
| CGRK            | Greek                                |
| HIST            | History                              |
| HARC            | History of Art and Architecture      |
| HUMA            | Humanities                           |
| IORP            | Industrial-Organizational Psychology |
| ISMT            | Information Systems Management       |
| ITAL            | Italian                              |
| JAPA            | Japanese                             |
| JOUR            | Journalism                           |
| LATI            | Latin                                |
| LSTU            | Legal Studies                        |
| MGMT            | Management                           |
| MATH            | Mathematics                          |
| MUSE            | Museum Studies                       |
| MUSI            | Music                                |
| NUTR            | Nutrition                            |
| PHIL            | Philosophy                           |
| PHYS            | Physics                              |
| PSYC            | Psychology                           |
| RELI            | Religion                             |
| SSCI            | Social Sciences                      |
| SOCI            | Sociology                            |
| SPAN            | Spanish Language and Literature      |
| SPCH            | Speech                               |
| STAT            | Statistics                           |
| STAR            | Studio Arts and Film                 |
+-----------------+--------------------------------------+
50 rows in set (0.01 sec)

PHP Script to Connect to Database and Get List of Departments

<?php

// set header for text content
header('Content-type: text/plain');

// use Dotenv to load database info from .env file
// DB_HOST, DB_USER, DB_PW, DB_NAME
require_once('vendor/autoload.php');
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->safeLoad();

// Connecting, selecting database
$mysqli = new mysqli($_ENV['DB_HOST'],$_ENV['DB_USER'],$_ENV['DB_PW'],$_ENV['DB_NAME']);
if ($mysqli->connect_errno) {
    echo "Failed to connect to mysql: ".$mysqli->connect_errno." ".$mysqli->connect_error;
}

// Performing SQL query
$query = 'SELECT DISTINCT department, department_code FROM ext_courses ORDER BY department';
$result = $mysqli->query($query);

// iterating through results
while ($row = $result->fetch_assoc()){
  echo $row['department_code'];
  echo "\t";
  echo $row['department'];
  echo "\n";
}
?>

Output

Turn this into HTML Output

<?php
// use Dotenv to load database info from .env file
// DB_HOST, DB_USER, DB_PW, DB_NAME
require_once('vendor/autoload.php');
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->safeLoad();

// Connecting, selecting database
$mysqli = new mysqli($_ENV['DB_HOST'],$_ENV['DB_USER'],$_ENV['DB_PW'],$_ENV['DB_NAME']);
if ($mysqli->connect_errno) {
    echo "Failed to connect to mysql: ".$mysqli->connect_errno." ".$mysqli->connect_error;
}

// Performing SQL query
$query = <<<ENDQUERY
SELECT
    DISTINCT department, department_code
FROM
    ext_courses
ORDER BY
    department
ENDQUERY;

$result = $mysqli->query($query);

// iterating through results
echo "<ul>\n";
while ($row = $result->fetch_assoc()) {
  echo "<li>";
    echo $row['department'];
    echo "</li>\n";
 }
echo "</ul>\n";

// cleanup query result and close connection
$query_result->free();
$mysqli->close();
?>

The entire "departments-simple.php"

<!DOCTYPE html>
<html>
 <head>
  <title>Departments</title>
  <link rel="stylesheet" href="styles/site.css" />
 </head>
 <body>
<h1>Harvard Extension School</h1>
<h2>Departments</h2>

<?php
// use Dotenv to load database info from .env file
// DB_HOST, DB_USER, DB_PW, DB_NAME
require_once('vendor/autoload.php');
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->safeLoad();

// Connecting, selecting database
$mysqli = new mysqli($_ENV['DB_HOST'],$_ENV['DB_USER'],$_ENV['DB_PW'],$_ENV['DB_NAME']);
if ($mysqli->connect_errno) {
    echo "Failed to connect to mysql: ".$mysqli->connect_errno." ".$mysqli->connect_error;
}

// Performing SQL query
$query = <<<ENDQUERY
SELECT
    DISTINCT department, department_code
FROM
    ext_courses
ORDER BY
    department
ENDQUERY;

$result = $mysqli->query($query);

// iterating through results
echo "<ul>\n";
while ($row = $result->fetch_assoc()) {
  echo "<li>";
    echo $row['department'];
    echo "</li>\n";
 }
echo "</ul>\n";

// cleanup query result and close connection
$query_result->free();
$mysqli->close();
?>

<footer>
  <p>This is a learning example to demonstrate PHP and mysql for the courses CSCI E-12 and CSCI S-12 taught by David Heitmeyer.  <br/>
The real <a href="https://courses.dce.harvard.edu/">Harvard Extension School course search</a> is at: <a href="https://courses.dce.harvard.edu/">courses.dce.harvard.edu</a></p>
</footer>
 </body>
</html>

Adding another view - Department Course Listings

Create another PHP file that displays course information based upon a department_code parameter.

Need to link to to courses.php:

Modify the department listing to include the hyperlink:


// Printing results in HTML
echo "<ul>\n";
while ($row = $result->fetch_assoc()) {
  echo "<li>";
  echo "<a href=\"courses.php?department_code=$row[department_code]\">"
  echo "$row[department]"
  echo "</a>";
  echo "</li>\n";
}
echo "</ul>\n";

courses.php

<!DOCTYPE html>
<html>
 <head>
  <meta charset="UTF-8"/>
  <title>Harvard Extension Courses</title>
  <link rel="stylesheet" href="styles/site.css" type="text/css"/>
 </head>
 <body>
<h1>Harvard Extension Courses</h1>
<p><a href="departments.php">Return to Department List</a></p>
<?php

// use Dotenv to load database info from .env file
// DB_HOST, DB_USER, DB_PW, DB_NAME
require_once('vendor/autoload.php');
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->safeLoad();

// Connecting, selecting database
$mysqli = new mysqli($_ENV['DB_HOST'],$_ENV['DB_USER'],$_ENV['DB_PW'],$_ENV['DB_NAME']);
if ($mysqli->connect_errno) {
    echo "Failed to connect to mysql: ".$mysqli->connect_errno." ".$mysqli->connect_error;
}

$dept_code = $_GET['department_code'];
$sqlescaped_dept_code = $mysqli->real_escape_string($dept_code);
$dept_code_html = htmlentities($dept_code);
?>
<h2>Department - <?php echo $dept_code_html ?></h2>
<?php
// Performing SQL query
$query = <<<ENDQUERY
SELECT
  department,
  department_code,
  course_number,
  term,
  academic_year,
  short_title,
  title,
  description,
  faculty_description
FROM
  ext_courses
WHERE
  department_code = '$sqlescaped_dept_code'
ORDER BY
  department,
  course_number,
  title
ENDQUERY;

$result = $mysqli->query($query);

// Printing results in HTML

$i = 0;
while ($row = $result->fetch_assoc()) {
  // calculate year
  $academic_year_display = $row['academic_year'];
  if ($row['term'] == 'Spring' or $row['term'] == 'January') {
    $academic_year_display += 1 ;
  }

  $course_content = <<<ENDCONTENT
  <section class="course">
  <h2 class="abbrev"> $row[short_title] </h2>
  <div>
    <p class="term">$row[term] $academic_year_display</p>
    <p class="title"><strong>$row[title]</strong></p>
    <p class="faculty">$row[faculty_description]</p>
    <p class="description">$row[description]</p>
  </div>
  </section>
ENDCONTENT;
  echo($course_content);
}


// cleanup query result and close connection
$query_result->free();
$mysqli->close();
?>
<footer>
<p><a href="./">PHP/mysql example list</a></p>
    <p>This is a learning example to demonstrate PHP and mysql for the courses CSCI E-12 and CSCI S-12 taught by David Heitmeyer.  <br/>
  The real <a href="https://courses.dce.harvard.edu/">Harvard Extension School course search</a> is at: <a href="https://courses.dce.harvard.edu/">courses.dce.harvard.edu</a>
    </p>
</footer>
</body>
</html>

Separation of Concerns

Separate the data the view using templates!

{{Mustache}} Templates

{{mustache}} is another widely used template system for JavaScript (and other languages!).

mustache

Mustache Departments

Mustache Template

mustache-dept.php

PHP

<?php
// Connecting, selecting database
  $mysqli = new mysqli('localhost','class','cscie12','coursecatalog');
  if ($mysqli->connect_errno) {
      echo "Failed to connect to mysql: ".$mysqli->connect_errno." ".$mysqli->connect_error;
  }

// Performing SQL query
$query = 'SELECT DISTINCT department, department_code  ext_courses ORDER BY department';
$result = $mysqli->query($query);

$i=0;
while ($row = $result->fetch_assoc()) {
  $results[$i++] = $row;
}

$template_data['departments'] = $results;

// Process with Mustache Template
include('lib/Mustache.php');

$m = new Mustache;
$template_file = 'mustache_templates/departments.html';
$template_contents = file_get_contents($template_file);
echo $m->render($template_contents, $template_data);

// cleanup query result and close connection
$query_result->free();
$mysqli->close();
?>

Mustache Template

mustache_templates/departments.html

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>Harvard Extension School - Departments</title>
  <link rel="stylesheet" href="styles/site.css" />
</head>

<body>
  <h1>Harvard Extension School</h1>
  <h2>Departments</h2>
  <ul>
    {{#departments}}
    <li>
      <a href="mustache-courses.php?department_code={{department_code}}">{{department}}</a>
    </li>
    {{/departments}}
  </ul>

  <footer>
    <p><a href="./">PHP/mysql example list</a></p>
    <p>This is a learning example to demonstrate PHP and mysql for the courses CSCI E-12 and CSCI S-12 taught by David
      Heitmeyer. <br />
      The real <a href="https://courses.dce.harvard.edu/">Harvard Extension School course search</a> is at: <a
        href="https://courses.dce.harvard.edu/">courses.dce.harvard.edu</a>
    </p>
  </footer>
</body>

</html>

Mustache Courses

<!DOCTYPE html>
<html lang="en">

<head>
  <title>Harvard Extension Courses in {{ department_name }}</title>
  <link rel="stylesheet" href="styles/site.css" />
  <meta charset="UTF-8" />
</head>

<body>
  <h1>Harvard Extension Courses in {{ department_name }}</h1>
  <p><a href="mustache-dept.php">Return to Department List</a></p>
  <h2>{{department_name}}</h2>
  <div>
    {{#courses}}
    <section class="course">
      <h2 class="abbrev">{{ short_title }}</h2>
      <div>
        <p class="term">{{ term }} {{ academic_year_display }}</p>
        <p class="title">{{ title }}</p>
        <p class="faculty">{{ faculty_description }}</p>
        <p class="description">{{{ description }}}</p>
      </div>
      </section>
    {{/courses}}
  </div>

  <footer>
    <p><a href="./">PHP/mysql example list</a></p>
    <p>This is a learning example to demonstrate PHP and mysql for the courses CSCI E-12 and CSCI S-12 taught by David
      Heitmeyer. <br />
      The real <a href="https://courses.dce.harvard.edu/">Harvard Extension School course search</a> is at: <a
        href="https://courses.dce.harvard.edu/">courses.dce.harvard.edu</a>
    </p>
  </footer>
</body>

</html>

Improving the Hello! Greeting

We started with

Without a "name", present the user a form. With a name, provide a greeting.

<?php
      $name = $_GET["name"];
?>
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Greeting Page</title>
  </head>
  <body>
    <?php
      if ($name) {
        echo("<h1>Hello, $name!</h1>");
      } else {
        echo('<h1><label for="input_name">Enter name:</label></h1>');
        echo('<form method="get">');
        echo('<input type="text" name="name" id="input_name"/>');
        echo('<br /><input type="submit" />');
        echo('<br /><input type="reset" />');
      }
    ?>
  </body>
</html>

Hello! Greeting, Improved

Three files: one code; two templates

index.php

<?php
$name = $_GET["name"];

// figure out which template is needed
if ($name) {
  $template_file = 'greeting.html';
} else {
  $template_file = 'form.html';
}
$template_contents = file_get_contents($template_file);
$template_data['name'] = $name;

// Process with Mustache Template
include('lib/Mustache.php');
$m = new Mustache;

echo $m->render($template_contents, $template_data);

?>

greeting.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Greeting Page for {{name}}</title>
  </head>
  <body>
      <h1>Hello, {{name}}!</h1>
  </body>
</html>

form.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Greeting Page</title>
  </head>
  <body>
      <h1><label for="input_name">Enter name:</label></h1>
      <form method="get">
      <input type="text" name="name" id="input_name"/>
      <br /><input type="submit" />
      <br /><input type="reset" />
  </body>
</html> 

CSR (Client Side Rendering)

Front-end JavaScript + templates and Back-end JSON

Departments

Courses

JSON PHP data

<?php

/// use Dotenv to load database info  .env file
// DB_HOST, DB_USER, DB_PW, DB_NAME
require_once('vendor/autoload.php');
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->safeLoad();

// Connecting, selecting database
$mysqli = new mysqli($_ENV['DB_HOST'],$_ENV['DB_USER'],$_ENV['DB_PW'],$_ENV['DB_NAME']);
if ($mysqli->connect_errno) {
    echo "Failed to connect to mysql: ".$mysqli->connect_errno." ".$mysqli->connect_error;
}

$dept_code = $_GET['department_code'];
$sqlescaped_dept_code = $mysqli->real_escape_string($dept_code);

// Performing SQL query
$query = <<<ENDQUERY
SELECT
  department,
  department_code,
  course_number,
  term,
  academic_year,
  short_title,
  title,
  description,
  faculty_description

  ext_courses
WHERE
  department_code = '$sqlescaped_dept_code'
ORDER BY
  department,
  course_number,
  title
ENDQUERY;

$query_result = $mysqli->query($query);

$i = 0;
while ($row = $query_result->fetch_assoc()) {
  // calculate year
  $academic_year_display = $row['academic_year'];
  if ($row['term'] == 'Spring' or $row['term'] == 'January') {
    $academic_year_display += 1 ;
  }
  $row['academic_year_display'] = $academic_year_display;

  $results[$i++] = $row;
}

$template_data['courses'] = $results;
$template_data['department_name'] = $dept_code;

header('Content-type: application/json');
echo json_encode($template_data);

// cleanup query result and close connection
$query_result->free();
$mysqli->close();
?>


Front-end courses

For example: CSCI courses (courses.html?department_code=CSCI)

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <title>Departments</title>
  <link rel="stylesheet" href="styles/site.css" />
  <script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.7/handlebars.min.js"
    integrity="sha512-RNLkV3d+aLtfcpEyFG8jRbnWHxUqVZozacROI4J2F1sTaDqo1dPQYs01OMi1t1w9Y2FdbSCDSQ2ZVdAC8bzgAg=="
    crossorigin="anonymous"></script>

  <script>
    let dataUrl = './json-courses.php';
    let urlParams = new URLSearchParams(window.location.search);
    console.log(urlParams.get('department_code'));
    let department_code = urlParams.get('department_code');
    document.addEventListener('DOMContentLoaded', function () {
      fetch(dataUrl + '?department_code=' + department_code)
        .then(response => response.json())
        .then(data => {
          console.log(data);
          let mysource = document.getElementById('courses-list-template').innerHTML;
          let mytemplate = Handlebars.compile(mysource);
          let myresult = mytemplate(data)
          document.getElementById('courses-list').innerHTML = myresult;
        });
    });
  </script>

</head>

<body>
  <h1>Harvard Extension School</h1>
  <p><a href="departments.html">Return to Department List</a></p>

  <div id="courses-list">

  </div>

  <div id="courses-list-template" class="handlebars">
    <h2>{{ department_name }}</h2>
    <p>{{ courses.length }} courses</p>
    <div>
      {{#courses}}
      <section class="course">
        <h2 class="abbrev">{{ short_title }}</h2>
        <div>
          <p class="term">{{ term }} {{ academic_year_display }}</p>
          <p class="title">{{ title }}</p>
          <p class="faculty">{{ faculty_description }}</p>
          <p class="description">{{{ description }}}</p>
        </div>
      </section>
      {{/courses}}
    </div>

    <footer>
      <p><a href="./">PHP/mysql example list</a></p>
      <p>This is a learning example to demonstrate PHP and mysql for the courses CSCI E-12 and CSCI S-12 taught by David
        Heitmeyer. <br />
        The real <a href="https://courses.dce.harvard.edu/">Harvard Extension School course search</a> is at: <a
          href="https://courses.dce.harvard.edu/">courses.dce.harvard.edu</a>
      </p>
    </footer>

</body>

</html>

JavaScript Frameworks - Vue, React, Angular, Ember

Understanding client-side JavaScript frameworks | MDN

JavaScript frameworks are an essential part of modern front-end web development, providing developers with tried and tested tools for building scalable, interactive web applications.

CSCI E-12 Resources

Vue directives are built into markup (e.g. v-for and v-bind). The advantage here is that Vue takes care of updating content when underlying data changes.

Snippet of Vue code that formats list of resources:


 <ul class="resources">
     <li v-for="r in urls" class="resource">
         <a v-bind:href="r.url">
           <img v-if="r.image" v-bind:src="r.image" />
         </a>
         <div class="title">
           <a v-bind:href="r.url">{{ r.title }}</a>
         </div>
         <div class="hostname">{{ r.hostname }}</div>
         <div class="description">{{ r.description }}</div>
     </li>
 </ul>

And the JSON data (snippet) that powers it:

{
   "urls": [
     {
       "url": "https://alistapart.com/",
       "title": "A List Apart",
       "description": "For people who make websites",
       "image": "https://i2.wp.com/alistapart.com/wp-content/uploads/2019/03/cropped-icon_navigation-laurel-512.jpg?fit=512%2C512&ssl=1"
     },
     {
       "url": "https://learn.jquery.com/",
       "title": "jQuery Learning Center",
       "keywords": "javascript, library",
       "image": "https://cscie12.dce.harvard.edu/images/site-card-jquery.png"
     },
     {
       "url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview",
       "title": "An overview of HTTP | MDN",
       "description": "HTTP is a protocol for fetching resources such as HTML documents. It is the foundation of any data exchange on the Web and it is a client-server protocol, which means requests are initiated by the recipient, usually the Web browser. A complete document is reconstructed  the different sub-documents fetched, for instance, text, layout description, images, videos, scripts, and more.",
       "image": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview/fetching_a_page.png"
     },
     {
       "url": "http://www.w3.org/",
       "title": "World Wide Web Consortium (W3C)",
       "description": "The World Wide Web Consortium (W3C) is an international community where Member organizations, a full-time staff, and the public work together to develop Web standards.",
       "image": "https://www.w3.org/Icons/WWW/w3c_home_nb-v.svg"
     }, ... ]}

Sending Email

Mail service -- e.g. Mailgun, Sendgrid, etc.

submit.php Example (uses Mailgun)

<?php require_once 'vendor/autoload.php';

     $loader = new \Twig\Loader\FilesystemLoader('./templates');
     $twig = new \Twig\Environment($loader, [
         'cache' => './compilation_cache',
         'debug' => true,
         'auto_reload' => true
     ]);
     $requestTime = new DateTime();
     $requestTime->setTimestamp($_SERVER['REQUEST_TIME']);
     $requestTimeHuman = $requestTime->format('Y-m-d\TH:i:s');

     $echocontent = $twig->render('form-response-template.html',
          [
          'getparams' => $_GET,
          'postparams' => $_POST,
          'httpheaders' => getallheaders(),
          'httpmethod' => $_SERVER['REQUEST_METHOD'],
          'serverinfo' => $_SERVER,
          'requesttime' => $requestTimeHuman,
          'httpreferer' => $_SERVER['HTTP_REFERER']
          ]);
     ?>


     <?php

     require 'vendor/autoload.php';
     use Mailgun\Mailgun;

     $mailto = filter_var($_POST['__mailto'], FILTER_VALIDATE_EMAIL);
     $mailkey = '';
     if (preg_match('/^csci(e|s)12\-(spring|summer|fall)-\d{4}-[a-z]+[0-9]+$/',$_POST['__mailkey'])) {
        $mailkey = $_POST['__mailkey'];
     }

     // only send if POST and if __mailto and if __mailkey exist

     if (strcmp($_SERVER['REQUEST_METHOD'],'POST') == 0 && $mailto && $mailkey ) {
       error_log("FormSubmit | MAILGUN | $mailkey | $mailto |");
       // First, instantiate the SDK with your API credentials
       $MG_API_KEY = getenv('MG_API_KEY');
       $MG_DOMAIN = getenv('MG_DOMAIN');
       $MG_ = getenv('MG_');

       $mg = Mailgun::create($MG_API_KEY); // For US servers
       $domain = $MG_DOMAIN;

       // Now, compose and send your message.
       // $mg->messages()->send($domain, $params);
       $mg->messages()->send($domain, [
         ''    => $MG_,
         'to'      => $mailto,
         'subject' => 'Form Submission',
         'html'    => $echocontent
       ]);
     }

     echo($echocontent);
     ?>

form_response_template.html

This is a PHP "Twig" template.

<DOCTYPE html>
     <html lang="en">
       <head><title>Form Submission</title>
         <style>
           body, * { font-family: helvetica, sans-serif; }
           body { margin: 1rem 5%; }
           h2 { margin-top: 1.5rem; }
           table, td, th, tr { border-collapse: collapse; }
           table td, table th { border-collapse: collapse; vertical-align: top; padding: 0.5rem; border: thin solid #101010; }
           table thead tr { color: #ffffff;  background-color: rgb(100,100,100); font-size: larger;}
           table tbody tr:nth-child(even) { background-color: rgb(240,240,240); }
           table tbody tr th { text-align: left; }
           footer { margin-top: 4rem; padding: 0.5rem; background-color: rgb(240,240,240); border-top: thin solid black; }
           footer p { margin-top: 0.5em; margin-bottom: 0.5em; }
         </style>
       </head>

       <body>
         <h1>Form Submission</h1>
         {% if getparams %}
         <h2>GET Parameters</h2>
         <table>
           <thead>
             <tr><th>Name</th><th>Value</th></tr>
           </thead>
           <tbody>
           {% for key, value in getparams %}
           <tr>
             <th>{{ key }}</th>
             <td>
               {% if value is iterable %}
               {% for v in value %}
                 {{ v }}{% if not(loop.last) %},<br/>{% endif %}
               {% endfor %}
               {% else %}
                 {{ value }}
               {% endif %}
             </td>
           </tr>
           {% endfor %}
           </tbody>
         </table>
         {% endif %}

         {% if postparams %}
         <h2>POST Parameters</h2>
         <table>
           <thead>
             <tr><th>Name</th><th>Value</th></tr>
           </thead>
           <tbody>
           {% for key, value in postparams %}
           <tr>
             <th>{{ key }}</th>
             <td>
               {% if value is iterable %}
               {% for v in value %}
                 {{ v }}{% if not(loop.last) %},<br/>{% endif %}
               {% endfor %}
               {% else %}
                 {{ value }}
               {% endif %}
             </td>
           </tr>
           {% endfor %}
           </tbody>
         </table>
         {% endif %}

         {% if serverinfo %}
         <h2>Request Information</h2>
         <table>
           <thead>
             <tr><th>Name</th><th>Value</th></tr>
           </thead>
           <tbody>
             <tr><th>Request Time</th><td>{{ requesttime }}</td></tr>
             <tr><th>Remote Address</th><td>{{ serverinfo['REMOTE_ADDR'] }}</td></tr>
             <tr><th>HTTP Referrer</th><td><a href="{{ httpreferer }}">{{ httpreferer }}</a></td></tr>
             <tr><th>HTTP Method</th><td>{{ httpmethod }}</td></tr>
           </tbody>
         </table>
         {% endif %}

         <footer>
           <p>This form submission tool is only for use by current students in <a href="https://cscie12.dce.harvard.edu/">CSCI E-12</a> and <a href="https://cscis12.dce.harvard.edu/">CSCI S-12</a> courses.</p><p>David Heitmeyer | <a href="https://extension.harvard.edu/">Harvard Extension School</a> | <a href="https://summer.harvard.edu/">Harvard Summer School</a></footer>
       </body>
      </html>

Approaches to eCommerce

Shopify

Shopify is a hosted ecommerce solution. It uses the “liquid” templating language (similar to Mustache or Handlebars, but more capable).

{% for image in product.images %}
    <img src="{{ image | img_url: '300x300' }}">
{% endfor %}

Commerce.js

Commerce.js describes itself as “Build eCommerce applications in vanilla JavaScript with our JS SDK and APIs. Create custom product displays, shopping carts, and checkouts with Commerce.js.

WooCommerce

WooCommerce is a popular ecommerce plugin used in WordPress

Oh, The Places You'll Go!

oh the places you'll go

Thank You!

<h1 data-to="Fall 2022 Class"
    data-from="David">
   Thank You!
</h1>