User Tools

Site Tools


component_class

This is an old revision of the document!


Component class

The component class is a base UI class providing a close binding between PHP and Javascript. The class is intended to be subclassed.

Simple component

In order to create a new, simple component just override the renderContent-function, such as:

class helloWorld extends Component {
 
  public function renderContent() {
    echo 'Hello world';
  }
}
 
$mycomponent = new helloWorld();
 
// Start page
 
$mycomponent->render();

Component properties

In order for components to work correctly, all variables needed for configuring the component should be implemented as properties. This can be done with the addPropertyMap function, which expect an array of property keys and default values.

To extend the component from above to make the text and text color configurable, do this:

class textOutput extends Component {
 
  public function __construct() {
    $this->addPropertyMap(array(
      'text' => 'Hello world',
      'color' => 'black'
    );
    parent::__construct();
  );
 
  public function renderContent() {
    echo '<span style="color:'.$this->color.';">';
    echo $this->text;
    echo '</span>';
  }
}
 
$mycomponent = new textOutput();
$mycomponent->text = 'Platform4PHP is cool';
$mycomponent->color = 'red';
$mycomponent->render();

Note how the configuration properties are easily set and read.

HTML output

The base component will render a div with the following properties:

  • The id will match the id set by the SetID() function. If no ID is set, one will be auto-generated.
  • It will add a class platform_component
  • It will add a class platform_component_CLASSNAME where CLASSNAME is the name of the class.
  • It will add up to three data-elements: redraw_url, componentclass and componentproperties for internal handling.

Example

output.html
<div class="platform_component platform_component_textoutput" id="example_output" data-componentproperties="..." data-redraw_url="..." data-componentclass="textOutput">
<span style="color:red;">Platform4PHP is cool</span>
</div>

Javascript and CSS handling

A component will typically need its own css-files and javascript to function properly. These can just be included in the constructor using the general Page::JSFile() and Page::CSSFile(). Platform will ensure that each file is only included once.

class textOutput extends Component {
 
  public function __construct() {
    Page::JSFile('script.js');
    Page::CSSFile('style.css');
    parent::__construct();
  );
 
}

In order for javascript to work, especially if the page is hyper-dynamic, it need to be wrapped in the following structure:

textoutput.js
  addPlatformComponentHandlerFunction('CLASS_IN_LOWERCASE', function(item) {
    // Do your stuff here!
  });

CLASS_IN_LOWERCASE should be exchanged with the class name of the PHP class in lowercase, so for the class textOutput, it should read like this:

textoutput.js
  addPlatformComponentHandlerFunction('textoutput', function(item) {
    // Do your stuff here!
  });

The item variable passed is a Jquery-selector pointing to the DOM node of the component. This will always point to a single node, so there is no need to iterate it. If several components of the same type exists, the function will be called multiple times.

Easy Javascript / PHP interaction

Components support easy interaction between Javascript and PHP. This interaction can both take place using forms and also directly from Javascript.

In javascript this interaction takes place through two JQuery plugins called componentIO and componentIOForm.

In PHP everything is handled by overriding the handleIO() function in the Component.

Easy form interaction

If you have a form, you can get your component to handle it. In javascript do this:

script.js
mycomponent.componentIOForm($('#myform'), function(data) { console.log('This is called on success.'); })

mycomponent is expected to be the jquery node for a valid component. myform is the HTML ID for a form. The anonymous function is called if the form is handled without errors.

When the form is submitted it will be intercepted by the component and the form output will end up in the handleIO() PHP function:

component.php
public function handleIO() : array {
  $form = new \Platform\Form(); // You need to get the appropriate form.
  if (! $form->validate) return ['status' => 0, 'form_errors' => $form->getAllErrors()];
  return ['status' => 1, 'message' => 'This entire array is returned to javascript'];
}

If you want the form to fail, you need to return an array with two keys. status which must be 0 or false, and form_errors which should contain the output from Form→getAllErrors(). This will automatic cause the frontend to fail the form.

Otherwise the array returned from the function will be passed into the javascript anonymous function.

Without javascript

It is possible to attach a form entirely from PHP like this:

component.php
  class myComponent {
    ...
    $form = new \Platform\Form(); // You need to get the appropriate form.
    $this->attachIOForm($form);
    ...
  }

When this form is submitted it is processed by the component like above, but without the need to write javascript-code.

Easy general interaction

If you just want to pass some variables to the handleIO()-function, you can also do that easily:

script.js
mycomponent.componentIO({action: 'setvalue', value: 'myvalue'}, function(data) { console.log('This is called with the return values from the PHP function.');})

This will immediately pass the variables to the handleIO()-function, where they can be handled.

component.php
public function handleIO() : array {
  if ($_POST['action'] == 'setvalue' && $_POST['value'] == 'myvalue') return ['status' => true, 'text' => 'This was exactly as expected.'];
  else return ['status' => false, 'text' => 'I didn\'t expect that input!'];
}

The return values will be passed back into the javascript anonymous functions.

Backend handling of events

It is possible to redirect javascript events to the backend. To do this use the registerEvent() function. This will redirect javascript events of the registered type to the backend. The event name will be passed in the $_POST['event'] variable and can be handled in the handleIO() function.

component.php
class MyComponent {
   ...
   $this->registerEvent('mycustomevent');
 
   public function handleIO() {
     if ($_POST['event'] == 'mycustomevent') {
       // Handle the custom event
     }
   }
}

On-the-fly javascript

If you set the script key on the array returned from the handleIO() function, then that value will be evaluated as javascript in the frontend, so you don't have to make a custom javascript file for minor functions.

  public function handleIO() {
    return ['script' => 'alert(\'This will cause an alert in the frontend!\');'];
  }

Property updates and redrawing

There are two more frontend effects that can be triggered from handleIO. The properties of the component can be updated by returning a new encoded property array in the properties-key, such as:

  public function handleIO() {
    return ['properties' => $this->getEncodedProperties()];
  }

If the component is redrawable, the redraw can also be executed by returning true in the redraw-key:

  public function handleIO() {
    return ['redraw' => true];
  }

Putting it all together

In this example we will make a component which prompts the user for a name and age, and then displays this information afterwards. This is obtained 100 % in PHP:

example.php
class myExample extends Component {
 
  public $form = null;
 
  public function __construct() {
    // Set component properties
    $this->setPropertyMap([
      'name' => '',
      'age' => 0
    ]);
 
    // Construct form
    $this->form = new Form('name_age_form');
    $this->form->addField(new TextField('Name', 'name'));
    $this->form->addField(new TextField('Age', 'age'));
    $this->form->addField(new SubmitButton('Send', 'send'));
 
    // Attach form to component
    $this->attachIOForm($this->form);
 
    // Redirect the resetcomponent event to the backend
    $this->registerEvent('resetcomponent');
  }
 
  public function renderContent() {
    // Check if name is attached to component
    if ($this->name) {
      // Display text
      echo 'You have entered '.$this->name.' as name and '.$this->age.' as age.';
      // Display a link to reset the component
      $menuitem = new MenuItem('Reset component', '#TRIGGER=resetcomponent');
      $menuitem->render();
    } else {
      // Display the form
      $this->form->render();
    }
  }
 
  public function handleIO() {
    // Check if form is submitted.
    if ($this->form->isSubmitted()) {
      // Validate form
      $result = $this->form->validate();
      // Send error if not validated
      if (! $result) return ['status' => false, 'form_errors' => $form->getAllErrors()];
      // Get values and transfer to component properties
      $values = $this->form->getValues();
      $this->name = $values['name'];
      $this->age = $values['age'];
      // Return status, updated properties and a redraw request.
      return ['status' => true, 'properties' => $this->getEncodedProperties(), 'redraw' => true];
    }
    // Check if reset was triggered
    if ($_POST['event'] == 'resetcomponent') {
      // Clear properties
      $this->name = '';
      $this->age = 0;
      // Return updated properties and a redraw request.
      return ['properties' => $this->getEncodedProperties(), 'redraw' => true];
    }
  }
}

Components in headless scripts

If you use components in headless scripts, which are scripts that doesn't contain a complete html page, but are instead meant to be loaded dynamically, be sure to call the Page::setPagestarted() function before adding your components. Otherwise included javascript and css-files will not load correctly.

Component event model

Components are designed to work with the Javascript/Jquery event model, so communication is expected to take place by triggering events on the DOM node containing the component. There are some built-in events already available on all basic components:

eventEffect
redrawRedraws the component by fetching its content from the server. See below.

Automatic component redraw

It is possible for Platform-components to automatically redraw themselves if they are designed correctly. The condition for a component to be able to redraw itself, is that it must be able to do so based solely on the content of its properties. In other words, the component should be able to render by doing just the following:

$component = new textOutput();
$component->setPropertyMap(PROPERTIES NEEDED TO RENDER COMPONENT);
$component->render();

In this case, you can force the component to redraw, by just triggering the Javascript redraw event on it.

Advanced redrawing

If you make a component which isn't able to redraw itself, then you should overwrite the static variable:

protected static $can_redraw = false;

If a component is to redraw itself, it needs to know if it should validate itself for security reasons. By default it will fail to redraw if it can't detect a valid session.

To skip this check, then overwrite the static variable:

protected static $is_secure = false;

In this case everyone can replay the Ajax redraw request and see the content of the component.

component_class.1620516700.txt.gz · Last modified: 2021/05/08 23:31 by sahl

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki