PHP code example of getpop / component-model

1. Go to this page and download the library: Download getpop/component-model library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

getpop / component-model example snippets


Component("component3")->setProp({
  prop: "color",
  value: "red"
});

Component("component2")->setProp({
  componentpath: ["component3"],
  prop: "color",
  value: "green"
});

Component("component1")->setProp({
  componentpath: ["component2", "component3"],
  prop: "color",
  value: "blue"
});

// Layout on the left uses default configuration of thumbnail on top of the text
Component("post-layout")->setProp({
  prop: "classes",
  value: {
    wrapper: "",
    thumb: "",
    contentbody: ""
  }
});

// Layout on the center display a big thumbnail to the left of the text
Component("central-section")->setProp({
  componentpath: ["post-layout"],
  prop: "classes",
  value: {
    wrapper: "row",
    thumb: "col-sm-4",
    contentbody: "col-sm-8"
  }
});

// Layout on the floating window display a small thumbnail to the left of the text
Component("floating-window")->setProp({
  componentpath: ["post-layout"],
  prop: "classes",
  value: {
    wrapper: "media",
    thumb: "media-left",
    contentbody: "media-body"
  }
});

// Component hierarchy on server-side, eg: through PHP:
[
  "top-component" => [
    "components" => [
      "component-level1" => [
        "components" => [
          "component-level11" => [
            "components" => [...]
          ],
          "component-level12" => [
            "components" => [
              "component-level121" => [
                "components" => [...]
              ]
            ]
          ]
        ]
      ],
      "component-level2" => [
        "components" => [
          "component-level21" => [
            "components" => [...]
          ]
        ]
      ]
    ]
  ]
]

class SomeComponentProcessor extends AbstractComponentProcessor {

  const COMPONENT_SOMENAME = 'somename';

  function getSubcomponentsToProcess() {
  
    return array(
      COMPONENT_SOMENAME,
    );
  }

  function getSubcomponents($component) 
  {
    $ret = parent::getSubcomponents($component);

    switch ($component->name) {
      
      case self::COMPONENT_SOMENAME:
        
        $ret[] = self::COMPONENT_SOMELAYOUT1;
        $ret[] = self::COMPONENT_SOMELAYOUT2;
        break;
    }

    return $ret;
  }

  function getImmutableConfiguration($component, &$props) 
  {
    $ret = parent::getImmutableConfiguration($component, $props);

    // Print the components properties ...
    switch ($component->name) {
      case self::COMPONENT_SOMENAME:        
        $ret['description'] = __('Some description');
        $ret['showmore'] = $this->getProp($component, $props, 'showmore');
        $ret['class'] = $this->getProp($component, $props, 'class');
        break;
    }

    return $ret;
  }
  
  function initModelProps($component, &$props) 
  {
    // Implement the components properties ...
    switch ($component->name) {
      case self::COMPONENT_SOMENAME:
        $this->setProp($component, $props, 'showmore', false);
        $this->appendProp($component, $props, 'class', 'text-center');
        break;
    }

    parent::initModelProps($component, $props);
  }
  // ...
}

const COMPONENT_SOMENAME = 'somename';

list($component, $virtualcomponentatts) = \PoP\Engine\VirtualComponentUtils::extractVirtualcomponent($component);

$virtualcomponent = \PoP\Engine\VirtualComponentUtils::createVirtualcomponent($component, $virtualcomponentatts),

namespace PoP\Engine;
abstract class AbstractComponentProcessor {

  // ...
}

class SomeComponentProcessor extends \PoP\Engine\AbstractComponentProcessor {

  const COMPONENT_SOMENAME1 = 'somename1';
  const COMPONENT_SOMENAME2 = 'somename2';
  const COMPONENT_SOMENAME3 = 'somename3';

  function getSubcomponentsToProcess() {
  
    return array(
      COMPONENT_SOMENAME1,
      COMPONENT_SOMENAME2,
      COMPONENT_SOMENAME3,
    );
  }

  // Implement the components properties ...
  // ...
}

// Retrieve the PoP_ComponentProcessor_Manager object from the factory
$componentprocessor_manager = \PoP\Engine\ComponentProcessor_Manager_Factory::getInstance();

// Obtain the ComponentProcessor for component COMPONENT_SOMENAME
$processor = $componentprocessor_manager->getComponentProcessor(new \PoP\ComponentModel\Component\Component(SomeComponentProcessor::class, SomeComponentProcessor::COMPONENT_SOMENAME));

// Do something...
// $processor->...

class SomeComponentProcessor extends \PoP\Engine\AbstractComponentProcessor {

  function foo($component) 
  {
    // First obtain the value from the parent class
    $ret = parent::foo($component);

    // Add properties to the component
    switch ($component->name) 
    {
      case self::COMPONENT_SOMENAME1:
        
        // Do something with $ret
        // ...
        break;

      // These components share the same properties
      case self::COMPONENT_SOMENAME2:
      case self::COMPONENT_SOMENAME3:
        
        // Do something with $ret
        // ...
        break;
    }

    return $ret;
  }
}

class SomeComponentProcessor extends \PoP\Engine\AbstractComponentProcessor {

  function foo($component, &$atts) 
  {
    $ret = parent::foo($component, &$atts);

    // ...

    return $ret;
  }
}

class SomeComponentProcessor extends \PoP\Engine\AbstractComponentProcessor {

  function getSubcomponents($component) 
  {
    $ret = parent::getSubcomponents($component);

    switch ($component->name) 
    {
      case self::COMPONENT_SOMENAME1:
        
        $ret[] = self::COMPONENT_SOMENAME2;
        break;

      case self::COMPONENT_SOMENAME2:
      case self::COMPONENT_SOMENAME3:
        
        $ret[] = new \PoP\ComponentModel\Component\Component(LayoutComponentProcessor::class, LayoutComponentProcessor::COMPONENT_LAYOUT1);
        $ret[] = new \PoP\ComponentModel\Component\Component(LayoutComponentProcessor::class, LayoutComponentProcessor::COMPONENT_LAYOUT2);
        $ret[] = new \PoP\ComponentModel\Component\Component(LayoutComponentProcessor::class, LayoutComponentProcessor::COMPONENT_LAYOUT3);
        break;
    }

    return $ret;
  }
}

abstract class PostLayoutAbstractComponentProcessor extends \PoP\Engine\AbstractComponentProcessor {

  function getSubcomponents($component) {
  
    $ret = parent::getSubcomponents($component);

    if ($thumbnail_component = $this->getThumbnailComponent($component)) 
    {
      $ret[] = $thumbnail_component;
    }
    if ($content_component = $this->getContentComponent($component)) 
    {
      $ret[] = $content_component;
    }
    if ($aftercontent_components = $this->getAftercontentComponents($component)) 
    {
      $ret = array_merge(
        $ret,
        $aftercontent_components
      );
    }

    return $ret;
  }

  protected function getContentComponent($component) 
  {
    // Must implement
    return null;
  }
  protected function getThumbnailComponent($component) 
  {
    // Default value
    return self::COMPONENT_LAYOUT_THUMBNAILSMALL;
  }
  protected function getAftercontentComponents($component) 
  {
    return array();
  }
}

class PostLayoutComponentProcessor extends PostLayoutAbstractComponentProcessor {

  protected function getContentComponent($component) 
  {
    switch ($component->name) 
    {
      case self::COMPONENT_SOMENAME1:
        
        return self::COMPONENT_LAYOUT_POSTCONTENT;

      case self::COMPONENT_SOMENAME2:
      case self::COMPONENT_SOMENAME3:
        
        return self::COMPONENT_LAYOUT_POSTEXCERPT;
    }

    return parent::getContentComponent($component);
  }
  protected function getThumbnailComponent($component) 
  {
    switch ($component->name) 
    {
      case self::COMPONENT_SOMENAME1:
        
        return self::COMPONENT_LAYOUT_THUMBNAILBIG;

      case self::COMPONENT_SOMENAME3:
        
        return self::COMPONENT_LAYOUT_THUMBNAILMEDIUM;
    }

    return parent::getThumbnailComponent($component);
  }
  protected function getAftercontentComponents($component) 
  {
    $ret = parent::getAftercontentComponents($component);

    switch ($component->name) 
    {
      case self::COMPONENT_SOMENAME2:
        
        $ret[] = self::COMPONENT_LAYOUT_POSTLIKES;
        break
    }

    return $ret;
  }
}

// Initialize
new PostLayoutComponentProcessor();

function initModelProps($component, &$props) 
{
  // Set prop...
  // Set prop...
  // Set prop...

  parent::initModelProps($component, $props);
}

function initModelProps($component, &$props) 
{
  switch ($component->name) {
    case self::COMPONENT_MAP:
      // Component "map" is setting the default value
      $this->setProp($component, $props, 'orientation', 'vertical');

      // Obtain the value from the prop
      $orientation = $this->getProp($component, $props, 'orientation');

      // Set the value on "map-inner"
      $this->setProp([[SomeComponent::class, SomeComponent::COMPONENT_MAPINNER]], $props, 'orientation', $orientation);
      break;
  }

  parent::initModelProps($component, $props);
}

function initModelProps($component, &$props) 
{
  switch ($component->name) {
    case self::COMPONENT_MAPWRAPPER:
      $this->setProp([[SomeComponent::class, SomeComponent::COMPONENT_MAP]], $props, 'orientation', 'horizontal');      
      break;
  }

  parent::initModelProps($component, $props);
}

function getDatasource($component, &$props) 
{
  switch ($component->name) {
    case self::COMPONENT_WHOWEARE:
      return \PoP\ComponentModel\Constants\DataSources::IMMUTABLE;
  }

  return parent::getDatasource($component, $props);
}

function getDbobjectIds($component, &$props, $data_properties) 
{
  switch ($component->name) {
    case self::COMPONENT_WHOWEARE:
      return [13, 54, 998];
  }

  return parent::getDbobjectIds($component, $props, $data_properties);
}

function getDataloader($component) 
{
  switch ($component->name) {
    case self::COMPONENT_AUTHORARTICLES:
      return [Dataloader::class, Dataloader::DATALOADER_POSTLIST];
  }
    
  return parent::getDataloader($component);
}

protected function getImmutableDataloadQueryArgs($component, $props) 
{
  $ret = parent::getImmutableDataloadQueryArgs($component, $props);
  
  switch ($component->name) {
    case self::COMPONENT_AUTHORARTICLES:
      // 55: id of "Articles" category
      $ret['cat'] = 55;
      break;
  }

  return $ret;
}

protected function getMutableonrequestDataloadQueryArgs($component, $props) 
{
  $ret = parent::getMutableonrequestDataloadQueryArgs($component, $props);
  
  switch ($component->name) {
    case self::COMPONENT_AUTHORARTICLES:
    
      // Set the logged-in user id
      $cmsapi = \PoP\CMS\FunctionAPI_Factory::getInstance();
      $ret['author'] = $cmsapi->getCurrentUserID();
      break;
  }

  return $ret;
}

function getFilter($component) 
{
  switch ($component->name) {
    case self::COMPONENT_AUTHORARTICLES:
          
      return GD_FILTER_AUTHORARTICLES;
  }
  
  return parent::getFilter($component);
}

function getQueryhandler($component) 
{
  switch ($component->name) {
    case self::COMPONENT_AUTHORARTICLES:
      return GD_DATALOAD_QUERYHANDLER_LIST;
  }
  
  return parent::getQueryhandler($component);
}

function getImmutableHeaddatasetcomponentDataProperties($component, &$props) 
{
  $ret = parent::getImmutableHeaddatasetcomponentDataProperties($component, $props);

  switch ($component->name) {
    case self::COMPONENT_AUTHORARTICLES:
      // Make it not fetch more results
      $ret[GD_DATALOAD_QUERYHANDLERPROPERTY_LIST_STOPFETCHING] = true;
      break;
  }
  
  return $ret;
}

function initModelProps($component, &$props) 
{
  switch ($component->name) {
    case self::COMPONENT_AUTHORARTICLES:

      // Set the content lazy
      $this->setProp($component, $props, 'skip-data-load', true);
      break;
  }

  parent::initModelProps($component, $props);
}

function getLeafComponentFieldNodes($component, $props) 
{
  $ret = parent::getLeafComponentFieldNodes($component, $props);

  switch ($component->name) {
    case self::COMPONENT_AUTHORARTICLES:
      $ret[] = 'title';
      $ret[] = 'content';
      break;
  }

  return $ret;
}

function getRelationalComponentFieldNodes($component) 
{
  $ret = parent::getRelationalComponentFieldNodes($component);

  switch ($component->name) {
    case self::COMPONENT_AUTHORARTICLES:
    
      $ret['author'] = [
        GD_DATALOADER_USERLIST => [
          COMPONENT_AUTHORNAME,
        ]
      ];
      $ret['comments'] = [
        GD_DATALOADER_COMMENTLIST => [
          COMPONENT_COMMENTLAYOUT,
        ]
      ];
      break;
  }

  return $ret;
}

function getRelationalComponentFieldNodes($component) 
{
  $ret = parent::getRelationalComponentFieldNodes($component);

  switch ($component->name) {
    case self::COMPONENT_AUTHORARTICLES:
    
      $ret['author'] = [
        POP_CONSTANT_SUBCOMPONENTDATALOADER_DEFAULTFROMFIELD => [
          new \PoP\ComponentModel\Component\Component(SomeComponentProcessor::class, SomeComponentProcessor::COMPONENT_AUTHORNAME),
        ]
      ];
      $ret['comments'] = [
        POP_CONSTANT_SUBCOMPONENTDATALOADER_DEFAULTFROMFIELD => [
          new \PoP\ComponentModel\Component\Component(SomeComponentProcessor::class, SomeComponentProcessor::COMPONENT_COMMENTLAYOUT),
        ]
      ];
      break;
  }

  return $ret;
}

function executeGetData($ids) {
  
  $objects = array();

  // Fetch all objects with IDs $ids
  // ...
  
  return $objects;
}

function executeGetData($ids) {
  
  $cmsapi = \PoP\CMS\FunctionAPI_Factory::getInstance();
  $query = array(
    '

function getDatabaseKey() 
{
  return GD_DATABASE_KEY_POSTS;
}  

function getFieldprocessor() 
{
  return GD_DATALOAD_FIELDPROCESSOR_POSTS;
}

function getDbobjectIds($data_properties) {
  
  $ids = array();

  // Find the IDs of the objects to be fetched
  // ...
  
  return $ids;
}

function getDbobjectIds($data_properties) {
  
  // Simply return the global $post ID. 
  $vars = \PoP\ComponentModel\Engine_Vars::getVars();
  return array($vars['global-state']['queried-object-id']);
}

function getQuery($query_args) 
{
  $query = array();

  // Add all the conditions in $query, taking values from $query_args
  // ...

  return $query;
}

function executeQueryIDs($query) {
    
  $ids = array();

  // Find the IDs of the objects to be fetched
  // ...
  
  return $ids;
}

function getQuery($query_args) {
    
  return $query_args;
}

function executeQueryIDs($query) {
    
  $cmsapi = \PoP\CMS\FunctionAPI_Factory::getInstance();
  return $cmsapi->getPosts($query, [QueryOptions::RETURN_TYPE => ReturnTypes::IDS]);
}  

class ObjectTypeFieldResolver_Posts extends \PoP\Engine\AbstractObjectTypeFieldResolver {

  function getValue($resultitem, $field) {
  
    // First Check if there's a ObjectTypeFieldResolverExtension to implement this field
    $hook_value = $this->getHookValue(GD_DATALOAD_FIELDPROCESSOR_POSTS, $resultitem, $field);
    if (!\PoP\ComponentModel\GeneralUtils::isError($hook_value)) {
      return $hook_value;
    }    

    $cmsresolver = \PoP\CMS\ObjectPropertyResolver_Factory::getInstance();
    $cmsapi = \PoP\CMS\FunctionAPI_Factory::getInstance();
    $post = $resultitem;
    switch ($field) 
    {
      case 'tags' :
        $value = $cmsapi->getCustomPostTags($this->getId($post), [], array('fields' => 'ids'));
        break;

      case 'title' :
        $value = \PoP\CMS\HooksAPI_Factory::getInstance()->applyFilters('the_title', $cmsresolver->getPostTitle($post), $this->getId($post));
        break;
      
      case 'content' :
        $value = $cmsresolver->getPostContent($post);
        $value = \PoP\CMS\HooksAPI_Factory::getInstance()->applyFilters('pop_content_pre', $value, $this->getId($post));
        $value = \PoP\CMS\HooksAPI_Factory::getInstance()->applyFilters('the_content', $value);
        $value = \PoP\CMS\HooksAPI_Factory::getInstance()->applyFilters('pop_content', $value, $this->getId($post));
        break;
    
      case 'url' :

        $value = $cmsapi->getPermalink($this->getId($post));
        break;

      case 'excerpt' :
        $value = $cmsapi->getTheExcerpt($this->getId($post));
        break;

      case 'comments' :
        $query = array(
          'status' => 'approve',
          'type' => 'comment', 
          'post_id' => $this->getId($post),
          'order' =>  'ASC',
          'orderby' => 'comment_date_gmt',
        );
        $comments = $cmsapi->getComments($query);
        $value = array();
        foreach ($comments as $comment) {
          $value[] = $cmsresolver->getCommentID($comment);
        }
        break;
  
      case 'author' :
        $value = $cmsresolver->getPostAuthor($post);
        break;  
      
      default:
        $value = parent::getValue($resultitem, $field);
        break;
    }

    return $value;
  }
}

function getFieldDefaultDataloader($field) 
{
  switch ($field) 
  {
    case 'tags' :
      return GD_DATALOADER_TAGLIST;

    case 'comments' :
      return GD_DATALOADER_COMMENTLIST;

    case 'author' :
      return GD_DATALOADER_CONVERTIBLEUSERLIST;																													
  }

  return parent::getFieldDefaultDataloader($field);
}

class ObjectTypeFieldResolver_Posts_Hook extends \PoP\Engine\ObjectTypeFieldResolver_HookBase {

  function getClassesToAttachTo() {
    
    return array(
      [ObjectTypeFieldResolver::class, ObjectTypeFieldResolver::FIELDPROCESSOR_POSTS],
    );
  }

  function getValue($resultitem, $field, $fieldprocessor) 
  {
    $post = $resultitem;
    switch ($field) 
    {
      case 'disclaimer':
        return \PoP\Engine\MetaManager::getCustomPostMeta($fieldprocessor->getId($post), "disclaimer", true);
    }

    return parent::getValue($resultitem, $field, $fieldprocessor);
  }  
}

class TextFilterInputs extends TextFormInputsBase implements \PoP\ComponentModel\DataloadQueryArgsFilter
{
  public function filterDataloadQueryArgs(array &$query, $component, $value)
  {
    switch ($component->name) 
    {
      case self::COMPONENT_FILTERINPUT_SEARCH:
        $query['search'] = $value;
        break;
    }
  }
}

function getActionExecuterClass($component) {
  
  switch ($component->name) {
    case self::COMPONENT_SOMENAME:
  
      return SomeActionExecuter::class;
  }

  return parent::getActionExecuterClass($component);
}

function execute(&$data_properties) {
  
  // Execute some operation and return the results
  // ...
  return $results;
}

class ActionExecuter_Logout extends \PoP\Engine\AbstractActionExecuter {

  function execute(&$data_properties) 
  {
    if ('POST' == \PoP\Root\App::server('REQUEST_METHOD')) { 

      // If the user is not logged in, then return the error
      $vars = \PoP\ComponentModel\Engine_Vars::getVars();
      if (!$vars['global-userstate']['is-user-logged-in']) 
      {
        $error = __('You are not logged in.');
      
        // Return error string
        return array(
          GD_DATALOAD_QUERYHANDLERRESPONSE_ERRORSTRINGS => array($error)
        );
      }

      $cmsapi = \PoP\CMS\FunctionAPI_Factory::getInstance();
      $cmsapi->logout();

      return array(
        GD_DATALOAD_QUERYHANDLERRESPONSE_SUCCESS => true
      );
    }

    return parent::execute($data_properties);
  }
}

function execute(&$data_properties) 
{
  if ('POST' == \PoP\Root\App::server('REQUEST_METHOD')) 
  {
    // Function getFormData obtains the filled-in values in the form
    $form_data = $this->getFormData();

    $errors = array();
    if (empty($form_data['post_id'])) {
      $errors[] = __('We don\'t know what post the comment is for.');
    }
    if (empty($form_data['comment'])) {
      $errors[] = __('The comment is empty.');
    }    
    if ($errors) 
    {
      return array(
        GD_DATALOAD_QUERYHANDLERRESPONSE_ERRORSTRINGS => $errors
      );
    }

    $cmsapi = \PoP\CMS\FunctionAPI_Factory::getInstance();
    $comment_id = $cmsapi->insertComment($form_data);

    // Save the result
    $actionexecution_manager = \PoP\Engine\ActionExecution_Manager_Factory::getInstance();
    $actionexecution_manager->setResult($this->get_name(), $comment_id);

    // No errors => success
    return array(
      GD_DATALOAD_QUERYHANDLERRESPONSE_SUCCESS => true
    );      
  }

  return parent::execute($data_properties);
}

function prepareDataPropertiesAfterMutationExecution($component, &$props, &$data_properties) {
    
  parent::prepareDataPropertiesAfterMutationExecution($component, $props, $data_properties);

  switch ($component->name) {
    case self::COMPONENT_ADDCOMMENT:

      $actionexecution_manager = \PoP\Engine\ActionExecution_Manager_Factory::getInstance();
      if ($comment_id = $actionexecution_manager->getResult(GD_DATALOAD_ACTIONEXECUTER_ADDCOMMENT)) 
      {
        $data_properties[GD_DATALOAD_QUERYARGS]['

function getDataAccessCheckpoints($component, &$props) 
{
  switch ($component->name) {
    case self::COMPONENT_SOMECOMPONENT:
    
      return [CHECKPOINT_WHITELISTEDIP];
  }
  
  return parent::getDataAccessCheckpoints($component, $props);
}

function getRelevantPage($component, &$props) {
    
  switch ($component->name) {
    case self::COMPONENT_MYPOSTS_SCROLL:
    case self::COMPONENT_MYPOSTS_CAROUSEL:
    case self::COMPONENT_MYPOSTS_TABLE:

      return POP_PAGE_MYPOSTS;
  }

  return parent::getRelevantPage($component, $props);
}


class WhitelistedIPCheckpoint extends \PoP\Engine\AbstractCheckpoint {

  function validateCheckpoint() 
  {
    // Validate the user's IP
    $ip = get_client_ip();
    if (!$ip) {          
      return new \PoP\ComponentModel\Error\Error('ipempty');
    }

    $whitelisted_ips = array(...);
    if (!in_array($ip, $whitelisted_ips)) {      
      return new \PoP\ComponentModel\Error\Error('ipincorrect');
    }
  
    return parent::validateCheckpoint();
  }
}
 php
\PoP\Root\App::stockAndInitializeModuleClasses([([
    \PoP\ComponentModel\Component::class,
]);
javascript
// Component hierarchy encoded as JSON:
{
  "top-component": {
    components: {
      "component-level1": {
        components: {
          "component-level11": {
            ...
          },
          "component-level12": {
            components: {
              "component-level121": {
                ...
              }
            }
          }
        }
      },
      "component-level2": {
        components: {
          "component-level21": {
            ...
          }
        }
      }
    }
  }
}
 bash
composer analyse