Skip to content
Description of an architecture based on a server-side component model
Branch: master
Clone or download

Latest commit

Fetching latest commit…
Cannot retrieve the latest commit at this time.

Files

Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.gitignore
LICENSE.md
README.md

README.md

PoP

PoP

This repo contains only documentation concerning the component-model architecture. All actual code (and their corresponding documentation) is found on all the different repositories under the PoP organization account.

Description

PoP describes an architecture based on a server-side component model. It has been implemented in PHP, but can also be considered a mental model for building applications in any language.

PoP is components all the way down. Each component is implemented partly in the back-end, and partly in the front-end. The component-based architecture provides the mechanism to build, configure and even deploy the application (eg: by providing support for the serverless paradigm).

In PoP, everything is a module

CMS-agnostic, based on contracts

PoP relies on contracts to interact with the underlying CMS or framework, where all logic resides. As such, it is CMS-agnostic, and it can work with any PHP-based CMS or framework (WordPress, Symfony, Laravel, Joomla, Drupal).

So far only the contracts for WordPress have been implemented, but extending it to any other platform is very simple: Only all the repos ending on "-wp", which contain the implementation of the contracts for WordPress, need be re-implemented.

No creeping business logic

PoP doesn't implement any business logic, and doesn't attempt to re-invent the wheel: Authentication, CRUD operations, validation, etc are all implemented by the CMS; PoP is simply a layer which makes use of all this already-existing functionality, and makes it easily available to the application.

Design goals

PoP's architecture attempts to achieve the following goals:

High level of modularity:

  • Strict top-down module hierarchy: Ancestor modules know their descendants, but not the other way around
  • One-way setting of props across modules, from ancestors to descendants
  • Configuration values are set through an API instead of through the application

Minimal effort to produced a maximum output:

  • Isomorphism of code
  • Output for different applications (website, mobile app, emails, etc)

Maintainable/Easy to debug and fix:

  • Modules are focused on a single task or goal

Aggressive caching, implemented across several layers:

  • Server-side caching
  • HTTP caching
  • Asset caching and, in addition, content-caching through CDN, service workers and local storage in client

Deployable on serverless PHP

  • Server-side components are the perfect mechanism to execute atomic operations on a serverless environment

Self documentation:

  • Component pattern libraries are automatically generated by rendering each module on their own

Install

Follow the instructions in:

(Other projects coming soon...)

Architecture foundations

The architecture establishes the following foundations:

  1. Everything is a module (also called component)
  2. The module is its own API

1. Everything is a module

A PoP application contains a top-most module (also called a component) which wraps other modules, which themselves wrap other modules, and so on until reaching the last level:

Sequence of modules wrapping modules wrapping modules, from an avatar all the way up to the webpage

Hence, in PoP everything is a module, and the top-most module represents the page.

2. The module is its own API

Every module, at whichever level inside the component hierarchy (i.e. the composition of modules starting from the top-most, all the way down to the last level), is independently accessible simply by passing along its module path in the URL: /page-url/?output=json&modulefilter=modulepaths&modulepaths[]=path-to-the-module

Progressive/Resilient components

In most libraries/frameworks in the market, the implementation of the concept of components is based on JavaScript. In PoP, a component has a progressive approach, and its implementation spans from back to front-end:

Back-endFront-end
Component hierarchy
Data loading
Configuration
Props
Styles
View
Reactivity

Response specification

The output from requesting a URL can contain several layers: At its core it is a data layer (enough for implementing an API), which can be further extended by a configuration layer (to implement a website).

1. Data layer

The data layer represents data in the following way:

  • Database data is retrieved through a relational structure under section databases
  • The IDs which are the results for each component are indicated through entry dbobjectids (under section datasetmoduledata)
  • Where to find those results in the database is indicated through entry dbkeys (under section modulesettings)
  • All database data is normalized (i.e. not repeated)

The API response looks like this:

{
  databases: {
    primary: {
      posts: {
        1: {
          author: 7, 
          comments: [88]
        },
        2: {
          recommendedby: [5], 
          comments: [23]
        },
      },
      users: {
        5: {
          name: "Leo"
        },
        7: {
          name: "Pedro"
        },
        18: {
          name: "Romualdo"
        }
      },
      comments: {
        23: {
          author: 7, 
          post_id: 2, 
          content: "Great stuff!"
        },
        88: {
          author: 18, 
          post_id: 1, 
          content: "I love this!"
        }
      }
    }
  },
  datasetmoduledata: {
    "topmodule": {
      modules: {
        "datamodule1": {
          dbobjectids: [1], 
        },
        "datamodule2": {
          dbobjectids: [2], 
        }
      }
    }
  },
  modulesettings: {
    "topmodule": {
      modules: {
        "datamodule1": {
          dbkeys: {
            id: "posts",
            author: "users",
            comments: "comments"
          }
        },
        "datamodule2": {
          dbkeys: {
            id: "posts",
            recommendedby: "users",
            comments: "comments"
          }
        }
      }
    }
  }
}

2. Configuration layer

The configuration layer can provide those properties and values required to build any kind of application:

{
  modulesettings: {
    "topmodule": {
      modules: {
        "layoutpostmodule": {
          configuration: {
            class: "text-center"
          },
          modules: {
            "titlemodule": {
              configuration: {
                class: "title bg-info",
                htmltag: "h3"
              }
            },
            "postcontentmodule": {
              configuration: {
                maxheight: "400px"
              },
              modules: {
                "authoravatarmodule": {
                  configuration: {
                    class: "img-thumbnail",
                    maxwidth: "50px"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Success stories

PoP is the foundation for the GraphQL API for PoP, an exceptional implementation of GraphQL which supports features not typically supported in GraphQL: HTTP caching, composable fields, composable directives, linear complexity time to resolve queries, and native federation and decentralization, among others.

In the near future, PoP will enable to build websites and export them as static.

Documentation

Alongside the code, each repository on the PoP organization account contains its corresponding technical documentation, in its README file.

Currently, most of the technical documentation is found on these repositories:

Articles concerning PoP

The following articles concern how different features in PoP were implemented:

🔗 Intro to PoP API, a new GraphQL server in PHP: Description of how the GraphQL API for PoP compares against a typical GraphQL

🔗 Demonstrating the PoP API, an implementation of GraphQL on steroids: Step-by-step description of solving a complex use case using the GraphQL API for PoP

🔗 Abstracting WordPress Code To Reuse With Other CMSs: Concepts (Part 1) and Implementation (Part 2): Design and implementation of strategies to make PoP become CMS-agnostic

🔗 “Create Once, Publish Everywhere” with WordPress: How through the WordPress editor Gutenberg” a PoP application can export data to be consumed in different mediums or platforms (website, app, emails, etc)

🔗 Introducing the Component-based API: Article describing all the main concepts of the PoP architecture

🔗 Caching Smartly In The Age Of Gutenberg: Caching mechanism implemented in PoP, allowing to cache pages even when the user is logged-in (to be emulated for Gutenberg)

🔗 Avoiding The Pitfalls Of Automatically Inlined Code: How PoP generates JS/CSS resources to improve performance

🔗 Sending Emails Asynchronously Through AWS SES: Mechanism to send emails through AWS SES implemented for PoP

🔗 Adding Code-Splitting Capabilities To A WordPress Website Through PoP: How PoP implements code-splitting of JavaScript files

🔗 How To Make A Dynamic Website Become Static Through A Content CDN: Mechanism implemented for PoP to route dynamic content through a CDN to improve performance

🔗 Implementing A Service Worker For Single-Page App WordPress Sites: The strategy behind the creation of the service-worker.js file in PoP (when running under WordPress), which powers its offline-first caching strategy

🔥 Become involved!

Contributors are welcome! Please check PoP in PHP to see what we need help with. If either you want to get involved, or simply find out more about PoP, simply send Leo an email or tweet 😀❤️.

You can’t perform that action at this time.