Quitus Suite Menu and CliFou Module
Quitus - Small Business Suite built by AI

Quitus Suite Menu and CliFou Module

In this article, we have two objectives. The first is to present the general menu of the Quitus Business Suite by utilizing an instance of the QuitusSuite class. By invoking its upcoming browse() method, we will be able to display the global menu as follows:

// It should be as easy as this...
$quitus = new QuitusSuite();
$quitus->browse();        
The Quitus Suite with an extended list of modules (fake representation for the time being) - Future objective

Of course, in our case, we will have a limited list of modules: one dedicated to Customers and Suppliers, one for Products (services/articles/products), one for Invoices, and one for Stock Management.

When clicking on the icon of the CliFou Module, we should be redirected to another page of our Business Suite that is dedicated to that specific module (we will discuss how to achieve this later). This is our intention for this third article.

Modules of a Suite

The list of modules contained in the Quitus Business Suite is actually stored in an XML file. This makes it easy to add or remove modules. Here's the simplest config.xml file:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LSVaesoli xmlns:xi="https://www.w3.org/2001/XInclude"
           xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
           xmlns:vae="urn:lato-sensu-management/Vaesoli"
           xmlns:quitus="urn:lato-sensu-management/Quitus">
  <QuitusSuite active="true">
    <Module name="clifou"   class="ClifouModule"    active="true"><![CDATA[trql.quitus.clifou.module.class.php]]></Module>
    <Module name="invoices" class="InvoicesModule"  active="true"><![CDATA[trql.quitus.invoices.module.class.php]]></Module>
    <Module name="products" class="ProductsModule"  active="true"><![CDATA[trql.quitus.products.module.class.php]]></Module>
    <Module name="stock"    class="StockModule"     active="true"><![CDATA[trql.quitus.stock.module.class.php]]></Module>
    </QuitusSuite>
</LSVaesoli>        

To deactivate a module, we can either remove its entire line from the XML file or set the "active" attribute of the corresponding module to "false."

I have tested this, and when no config.xml file is found or if the .xml file does not contain any modules, the test code does not perform any actions, which is exactly what I expected. In our case, nothing could have been done since we still have an empty QuitusSuite class.

QuitusSuite : read the config file

As we are just starting with the code, I will include all sorts of debug messages that can help us build the code step by step.

/* ==================================================== */
/** {{*readConfig()=

    The configuration file maintains all inner details of a Quitus Suite

    {*params
    *}

    {*return
        (self)      The current instance of the class
    *}

    {*example
    *}

    *}}
*/
/* ==================================================== */
public function readConfig()
{
    echo "<p>{$this->home}</p>\n";
    echo "<p>{$this->name}</p>\n";

    if ( is_null( $this->name ) )
        $file = v::FIL_AddBS( $this->home ) . 'config.xml';
    else
        $file = v::FIL_AddBS( $this->home ) . "{$this->name}.config.xml";

    if ( is_file( $file ) )
    {
        $oDom = new \DomDocument();

        echo "<p>{$file} FOUND</p>\n";

        if ( @$oDom->Load( $file ) )
        {
            //echo "<p>{$file} LOADED</p>\n";

            $oXPath = new \DOMXPath( $oDom );

            if ( $oXPath && ( $o = $oXPath->query( 'QuitusSuite' ) ) && $o->length > 0 )
            {
                $suiteNode = $o->item(0);
                echo "<p>{$file} ROOT FOUND</p>\n";

                if ( ( $modulesColl = $oXPath->query( 'Module',$suiteNode ) ) && ( $modulesColl->length > 0 ) )
                {
                    echo "<p>{$modulesColl->length} modules found</p>\n";

                    foreach( $modulesColl as $module )
                    {
                        if ( $active = v::MISC_CastBool( $module->getAttribute( 'active' ),true  ) )
                        {
                            $name   = $module->getAttribute( 'name'  );
                            $class  = $module->getAttribute( 'class' );
                            $src    = $module->nodeValue;

                            echo "<p>{$name} - {$class} - {$src}</p>\n";

                            require_once( $src );
                            $className = "trql\\quitus\\" . $class;
                            $this->addModule( $name,new $className( $this ) );   
                        }   /* if ( $active = ... ) */
                    }   /* foreach( $modulesColl as $module ) */
                }   /* if ( ( $modulesColl = $oXPath->query( 'Module',$moduleNode ) ) && ( $modulesColl->length > 0 ) ) */
            }   /* if ( $oXPath && ( $moduleNode = $oXPath->query( 'QuitusSuite' ) ) ) */
        }   /* if ( @$oDom->Load( $file ) ) */
    }   /* if ( is_file( $file ) ) */
    else
    {
        echo "<p>{$file} NOT FOUND</p>\n";
    }
}   /* End of QuitusSuite.readConfig() */        

At first, this should work. Let's try it:

Fatal error: Uncaught Error: Call to undefined method trql\quitus\QuitusSuite::addModule() in trql.quitus.suite.class.php:329 Stack trace: #0 trql.quitus.suite.class.php(230): trql\quitus\QuitusSuite->readConfig() #1        

Oops ... We haven't create the addModule() method of the QuitusSuite. Let's do this right away. First, I'll review a bit how the QuitusSuite class gets defined (abstract does not seem appropriate):

class QuitusSuite extends CreativeWork
{
    /* === [Properties NOT defined in schema.org] ===================== */
    public      $wikidataId     = 'Q1143070';                           /* {*property   $wikidataId     (string)                Wikidata ID. Software suite: application suite, suite, software collection,
                                                                                                                                software set, software group, software tool set, software tool kit, software
                                                                                                                                toolkit  *} */
    public      $image          = '/media/images/quitus-suite.jpg';     /* {*property   $image          (string|null)           The illustration of the Quitus Suite. Reset at [c]__construct()[c] time. *} */
    public      $modules        = [];                                   /* {*property   $modules        (array|null)            The list of modules contained in the Quitus Suite *} */
    public      $parentSuite    = null;                                 /* {*property   $parentSuite    (QuitusSuite|null)      The suite this suite is part of. [c]null[/c] by default. *} */
    public      $home           = null;                                 /* {*property   $home           (string|null)           Where quitus data are stored *} */

    /* ================================================== */
    /** {{*__construct( [$suite[,$home]] )=

        Class constructor

        {*params
            $suite     (QuitusSuite|null)   The parent suite of this suite. Optional.
            $home      (string|null)        The home directory of the suite (where data gets stored)
        *}

        {*return
            (self)      The current instance of the class
        *}

        {*keywords
            constructors, destructors
        *}

        {*seealso
            @fnc.__destruct
        *}

        {*warning
            This is the first step in using the "Quitus Suite". The code is therefore
            not stable and not finished (it doesn't cover everything a Quitus module
            should).
        *}

        {*example
        *}

        *}}
    */
    /* ================================================== */
    public function __construct( $suite = null,$home = null )
    {
        parent::__construct();
        $this->updateSelf( __CLASS__,'/q/common/trql.classes.home/' . basename( __FILE__,'.php' ),$withFamily = false );

        if ( empty( $home ) )
            $this->home = v::FIL_RealPath( $_SERVER['DOCUMENT_ROOT'] . '/../databases' );
        else
            $this->home = $home;

        if ( $suite )
            $this->parentSuite = &$suite;

        $this->readConfig();

        return ( $this );
    }   /* End of QuitusSuite.__construct() */


    [... here the readConfig() method]

    /* ================================================== */
    /** {{*addModule( $name,$module )=

        Adds a Quitus module in the Quitus Suite

        {*params
            $name       (string)            Name of the module
            $module     (QuitusModule)      The Quitus module to add to the Quitus Suite
        *}

        {*return
            (self)      Returns the current instance of the class.
        *}

        {*seealso
            @fnc.hasModules
        *}

        {*example
        *}

        *}}
    /* ================================================== */
    public function addModule( $name,$module )
    {
        $this->modules[ $name ] = &$module;

        return ( $this );
    }   /* End of QuitusSuite.addModule() */
}   /* End of class QuitusSuite */        

Another try ...

Fatal error
: Uncaught Error: Call to undefined method trql\quitus\QuitusSuite::browse() in index.php:40        

Oops another error: the browse() method hasn't been defined. Jesus. Let's define one:

/* ==================================================== */
/** {{*browse()=

    Browse the Quitus Modules contained in the Quitus Suite and present them as
    clickable icons.

    {*params
    *}

    {*return
        (string)        Returns the HTML that must be displayed to show all the
                        modules contained in the Quitus Suite. Each module is
                        presented as a clickable item that is redirecting the
                        user to the specific module
    *}

    {*seealso
    *}

    {*example
    *}

    *}}
*/
/* ==================================================== */
public function browse()
{
    $html = '';

    foreach ( $this->modules as $module )
    {
        $parentClass = ( array_keys( class_parents( $module ) ) )[0];
        $param       = 'module';

        if ( $parentClass ===  'trql\quitus\QuitusSuite' )
            $param = 'suite';

        $html .= "<div class=\"quitus module tile shadow\">\n";
            $html .= "<a href=\"?{$param}={$module->identifier}\" target=\"_blank\">\n";
                $html .= $module->iconize();
            $html .= "</a> <!-- -->\n\n";

            $html .= "<div class=\"quitus module name\">\n";
                $html .= "<p>{$module->name}</p>\n";
            $html .= "</div> <!-- .quitus.module.name -->\n";
            $html .= "<div class=\"quitus module description\">\n";
                $html .= "<p>{$module->description}</p>\n";
            $html .= "</div> <!-- .quitus.module.description -->\n";
        $html .= "</div> <!-- .quitus.module.tile -->\n";
    }   /* foreach ( $this->modules as $module ) */

    return ( $html );
}   /* End of QuitusSuite.browse() */        

The browse() method of the Quitus suite browses through the modules that are part of the suite and requests each of them to iconize itself. Let's move on with another try:


The Quitus Business Suite with 4 modules

Great! We have what we expected.

Click on the CliFou Module in the Menu

Working with the test file of IllicoDB3 is not a very good idea. Therefore, I will create a specific test code for the Quitus Suite:

<?php 
use \trql\vaesoli\Vaesoli       as v;
use \trql\quitus\QuitusSuite    as QuitusSuite;

{   /* Load classes */
    if ( ! defined( 'VAESOLI_CLASS_VERSION' ) )
        require_once( "{$_SERVER['snippet-center']}/trql.vaesoli.class.php" );

    if ( ! defined( 'QUITUS_SUITE_CLASS_VERSION' ) )
        require_once( "{$_SERVER['snippet-center']}/trql.quitus.suite.class.php" );

}   /* Load classes */
?>
<style>
</style>

<article id="quitusStartPage" class="content">
<?php
    $quitus = new QuitusSuite( null /*parentSuite */,$GLOBALS['oWebSite']->dataPath );

    if ( empty( $_GET['module'] ?? null ) && empty( $_GET['suite'] ?? null ) )
    {
        echo "<h1>Quitus Menu</h1>";

        echo "<section class=\"cobbles\">\n";
            echo $quitus->browse();
        echo "</section> <!-- .cobbles -->\n";
    }
?>
</article> <!-- #quitusStartPage -->        

What does this code: it simply creates the menu we have seen before. All the cobbles (one per module) is clickable ... this pass the name of the module as a parameter of the URL like in /?module=clifou

What does it do? Well, nothing! The module is mentioned but as the test code does not anticipate any parameter, it does not do much. Little modification of the test code:

<?php 
use \trql\vaesoli\Vaesoli       as v;
use \trql\quitus\QuitusSuite    as QuitusSuite;

{   /* Load classes */
    if ( ! defined( 'VAESOLI_CLASS_VERSION' ) )
        require_once( "trql.vaesoli.class.php" );

    if ( ! defined( 'QUITUS_SUITE_CLASS_VERSION' ) )
        require_once( "trql.quitus.suite.class.php" );
{   /* Load classes */
?>

<style>
</style>

<article id="quitusStartPage" class="content">
    <?php
        $quitus = new QuitusSuite( null /*parentSuite */,$GLOBALS['oWebSite']->dataPath );

        if ( empty( $_GET['module'] ?? null ) && empty( $_GET['suite'] ?? null ) )
        {
            echo "<h1>Quitus Menu</h1>";

            echo "<section class=\"cobbles\">\n";
                echo $quitus->browse();
            echo "</section> <!-- .cobbles -->\n";
        }
        elseif ( ! empty( $_GET['module'] ?? null ) )
        {
            $moduleName = strtolower( trim( $_GET['module'] ) );

            if ( isset( $quitus->modules[ $moduleName ] ) )
            {
                $module = $quitus->modules[ $moduleName ];
                $module->run();
            }
            else
            {
                echo "<p><b>{$moduleName}</b> module : NOT FOUND</p>";
            }
        }   /* elseif ( ! empty( $_GET['module'] ?? null ) ) */
        elseif ( ! empty( $_GET['suite'] ?? null ) )
        {
            // Here ... we might need to display the modules contained in a specific suite
        }   /* elseif ( ! empty( $_GET['suite'] ?? null ) ) */

    ?>
</article> <!-- #quitusStartPage -->        

If a module is passed as a parameter of the Quitus Business Suite page, we look for it in the list of modules included in the suite and request to run it ($module->run()). What does it produces? We will simply give it a try:

Fatal error: Uncaught Error: Call to undefined method trql\quitus\ClifouModule::run() in index.php:44        

That's right, the run() method hasn't been defined in the code of the class. I will define one in the Quitus Module abstract class just to check whether it works.

/* ==================================================== */
/** {{*run()=

    Runs the module

    {*params
    *}

    {*return
        (self)      The current instance of the class
    *}


    {*seealso
        @fnc.browse, @fnc.__toForm
    *}

    {*warning
        This is the first step in using a "Quitus" module. The code is therefore
        not stable and not finished (it doesn't cover everything a Quitus module
        should).
    *}

    {*example
    *}

    *}}
*/
/* ==================================================== */
public function run()
{
    echo $this->browse();
    echo $this->__toForm();

    return ( $this );
}   /* End of QuitusModule.run() */        

The run() method calls two additional methods: browse() and __toForm().

The browse() method is supposed to present the data of the module as an HTML table filled with data; the __toForm() method is supposed to present a form that will make it possible to change a record and submit it to the backend server. We'll, proceed slowly with that bearing in mind the little miracles we already obtained with IllicoDB3 ! Indeed, thanks to the inner Sermo instance included in IllicoDB3 we could generate the code of a browse and the code of a form; Sermo used the definition of the underlying data tables to generate that code.

First things first: first create the browse() and __toForm() method of a Quitus Module.

/* ==================================================== */
/** {{*browse()=

     Browse the items contained in the module (e.g. it will browse the invoices 
     for the invoices module, or the clifou entries, or the support tickets)

    {*params
    *}

    {*return
        (string)        HTML code
    *}


    {*seealso
        @fnc.run, @fnc.__toForm
    *}

    {*warning
        This is the first step in using a "Quitus" module. The code is therefore
        not stable and not finished (it doesn't cover everything a Quitus module
        should). It returns a dummy string for the time being
    *}

    {*example
    *}

    *}}
*/
/* ==================================================== */
public function browse() : string
{
    return ( 'I AM THE BROWSE' );
}   /* End of QuitusModule.browse() */

/* ==================================================== */
/** {{*__toForm()=

     Presents an HTML form to create/modify entries related tothe current module

    {*params
    *}

    {*return
        (string)        HTML code of the form
    *}


    {*seealso
        @fnc.run, @fnc.browse
    *}

    {*warning
        This is the first step in using a "Quitus" module. The code is therefore
        not stable and not finished (it doesn't cover everything a Quitus module
        should). It returns a dummy string for the time being
    *}

    {*example
    *}

    *}}
*/
/* ==================================================== */
public function __toForm() : string
{
    return ( 'I AM THE FORM' );
}   /* End of QuitusModule.__toForm() */        

We can try out the new classes. Here's what it produces:

I AM THE BROWSEI AM THE FORM        

Perfect. That is what I expected.

Link Between a Module and IllicoDB3

To benefit from the browse() method and __toForm() method of IllicoDB3, a Quitus Module must make the link with IllicoDB3.

There are two things to consider: (1) the IllicoDB3 DB and the (2) IllicoDB3 Table.

The DB is central to all modules contained in the same suite -- this makes this notion belonging to the suite; the table (or tables in case there are satellite tables) are set per module -- and therefore must be provided in a quitus module.

We may need to anticipate some fundamental changes here, I am afraid

Changes to QuitusSuite

Because the DB is central to the whole Quitus Business Suite, we need to make sure it gets reflected in the QuitusSuite class and where better than in the config file can we mention which IllicoDB3 DB is concerned?

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<LSVaesoli xmlns:xi="https://www.w3.org/2001/XInclude"
           xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
           xmlns:vae="urn:lato-sensu-management/Vaesoli"
           xmlns:quitus="urn:lato-sensu-management/Quitus">
  <QuitusSuite active="true">

    <!-- IllidoDB3 specific parameters FOR THE SUITE -->
    <IllicoDB3 name="Quitus">
    </IllicoDB3>

    <!-- List of modules composing the suite -->
    <Module name="clifou"   class="ClifouModule"    active="true" moduleClassSrc="trql.quitus.clifou.module.class.php">
      <Table name="contacts" />
    </Module>

    <Module name="invoices" class="InvoicesModule"  active="true" moduleClassSrc="trql.quitus.invoices.module.class.php">
      <Table name="invoices" />
    </Module>

    <Module name="products" class="ProductsModule"  active="true" moduleClassSrc="trql.quitus.products.module.class.php">
      <Table name="products" />
    </Module>

    <Module name="stock"    class="StockModule"     active="true" moduleClassSrc="trql.quitus.stock.module.class.php">
      <Table name="stock" />
    </Module>

  </QuitusSuite>
</LSVaesoli>        

We need to update the readConfig() method of the QuitusSuite class ... what will cahnge is the code needed to extract the table(s) per module:

public function readConfig()
{
  if ( is_null( $this->name ) )
      $file = v::FIL_AddBS( $this->home ) . 'config.xml';
  else
      $file = v::FIL_AddBS( $this->home ) . "{$this->name}.config.xml";

  if ( is_file( $file ) )
  {
    $oDom = new \DomDocument();

    //echo "<p>{$file} FOUND</p>\n";

    if ( @$oDom->Load( $file ) )
    {
      //echo "<p>{$file} LOADED</p>\n";

      $oXPath = new \DOMXPath( $oDom );

      if ( $oXPath && ( $o = $oXPath->query( 'QuitusSuite' ) ) && $o->length > 0 )
      {
        $suiteNode = $o->item(0);
        //echo "<p>{$file} ROOT FOUND</p>\n";

        if ( ( $modulesColl = $oXPath->query( 'Module',$suiteNode ) ) && ( $modulesColl->length > 0 ) )
        {
          //echo "<p>{$modulesColl->length} modules found</p>\n";

          foreach( $modulesColl as $module )
          {
            if ( $active = v::MISC_CastBool( $module->getAttribute( 'active' ),true  ) )
            {
              $name   = $module->getAttribute( 'name'  );
              $class  = $module->getAttribute( 'class' );
              $src    = $module->getAttribute( 'moduleClassSrc' );
              $tables = null;

              if ( ( $tableColl = $oXPath->query( 'Table',$module ) ) && ( $tableColl->length > 0 ) )
              {
                //echo "<p>FOUND TABLES</p>";

                // The tables of the module
                $tables = [];
                foreach( $tableColl as $tableNode )
                {
                    if ( ! empty( $tableName = $tableNode->getAttribute( 'name' ) ) )
                      $tables[] = $tableName;
                }   /* foreach( $tableColl as $tableNode ) */
                //var_dump( $tables );
              }   /* if ( ( $tableColl = $oXPath->query( 'Table',... ) */

              require_once( $src );
              $className = "trql\\quitus\\" . $class;
              $this->addModule( $name,new $className( $this,$tables ) );
            }   /* if ( $active = ... ) */
          }   /* foreach( $modulesColl as $module ) */
          //$this->title = $o->item(0)->nodeValue;
        }   /* if ( ( $modulesColl = $oXPath->query( 'Module',$moduleNode ) ) && ( $modulesColl->length > 0 ) ) */

        if ( ( $illico = $oXPath->query( 'IllicoDB3',$suiteNode ) ) && ( $illico->length > 0 ) )
        {
          $illicoDBNode = $illico->item(0);

          if ( ! empty( $DBName = $illicoDBNode->getAttribute( 'name' ) ) )
          {
            //echo "<p>FOUND IllicoDB3:{$DBName}</p>";
            $this->IllicoDB = new IllicoDB3( $DBName,$this->home );
            //echo "<p>{$this->IllicoDB->name} in {$this->IllicoDB->home()} IN " . __METHOD__ . " AT LINE " . __LINE__ . "</p>";
          }
          else
          {
            echo "<p>IllicoDB3 DB Name empty: should throw an exception IN " . __METHOD__ . " AT LINE " . __LINE__ . "</p>";
          }
        }   /* if ( ( $illico = $oXPath->query( 'IllicoDB3',$suiteNode ) ) && ( $illico->length > 0 ) ) */
      }   /* if ( $oXPath && ( $moduleNode = $oXPath->query( 'QuitusSuite' ) ) ) */
    }   /* if ( @$oDom->Load( $file ) ) */
  }   /* if ( is_file( $file ) ) */
  else
  {
    echo "<p>{$file} NOT FOUND</p>\n";
  }

  return ( $this );
}   /* End of QuitusSuite.readConfig() */        

As we also pass the table(s) to the constructor of a module, we need to make sure it can be received and stored. That makes it necessary to change the QuitusModule class as well.

/* ==================================================== */
/** {{*__construct( [$suite[,$tables]] )=

    Class constructor

    {*params
        $suite      (QuitusSuite)       Parent suite if any. Optional. [c]null[/c]
                                        by default
        $tables     (array)             Array of tables that must be considered by the
                                        module. Such tables refer to the global DB
                                        maintained in the parent suite of the module.
                                        [c]null[/c] by defaukt
    *}

    {*return
        (self)      The current instance of the class
    *}

    {*keywords
        constructors, destructors
    *}

    {*seealso
        @fnc.__destruct
    *}

    {*warning
        This is the first step in using a "Quitus" module. The code is therefore
        not stable and not finished (it doesn't cover everything a Quitus module
        should).
    *}

    {*example
    *}

    *}}
*/
/* ==================================================== */
public function __construct( $suite = null,$tables = null )
{
    parent::__construct();

    $this->parentSuite      = &$suite;           /* The parent suite of the module */
    $this->tables           = $tables;           /* The tables of the module */

    return ( $this );
}   /* End of QuitusModule.__construct() */
        

There are more things to do but I won't get into that at the moment as it will only make this article grow whereas I would like to concentrate on the browse() method of the QuitusModule class: the rest, you will discover that by yourself in the code that will be attached to this article.

QuitusModule : browse()

If possible, we would like our browse method to be relying on IllicoDB3 for this specific functionality. Actually, there will be no other alternative, at least at this point.

/* ==================================================== */
/** {{*browse()=

     Browse the items contained in the module (e.g. it will browse the invoices
     for the invoices module, or the clifou entries, or the support tickets)

    {*params
    *}

    {*return
        (string)        HTML code
    *}


    {*seealso
        @fnc.run, @fnc.__toForm
    *}

    {*warning
        This is the first step in using a "Quitus" module. The code is therefore
        not stable and not finished (it doesn't cover everything a Quitus module
        should).
    *}

    {*example
    *}

    *}}
*/
/* ==================================================== */
public function browse() : string
{
  // If we know what field(s) must be displayed in the browse
  if ( ! empty( $this->mainTableFields ) )
  {
    // If we have a pernt suite
    if ( ! empty( $this->parentSuite ) )
    {
      // If there is an illicoDB associated to the parent suite
      if ( ! empty( $this->parentSuite->IllicoDB ) )
      {
        //echo "<p>MAYBE THERE IS A BROWSE IN THE ILLICODB3 PROPERTY OF THE PARENT SUITE</p>";
        // If we can open the main DB
        if ( $success = $this->parentSuite->IllicoDB->open( $this->parentSuite->IllicoDB->name ) )
        {
          // This is supposed to be the main table of the module
          $mainTable = $this->tables[0];

          //echo "<p>DB OPEN; NEED TO OPEN THE MAIN TABLE NOW: {$mainTable}</p>";

          // If we can find the main table in the DB
          if ( $table = $this->parentSuite->IllicoDB->$mainTable )
          {
            //echo "<p>MAIN TABLE {$mainTable} IS OK</p>";
            // Return a BROWSE based on IllicoDB3
            return ( $table->browse( $this->mainTableFields,floor( $table->reccount() / 3 ) ) );
          }   /* if ( $table = $this->parentSuite->IllicoDB->$mainTable ) */
        }
        else
        {
            echo "<p>LA DB N'EST PAS OUVERTE</p>";
        }
      }   /* if ( ! empty( $this->parentSuite->IllicoDB ) ) */
    }   /* if ( ! empty( $this->parentSuite ) ) */
  }   /* if ( ! empty( $this->mainTableFields ) ) */

  return ( 'I AM THE BROWSE OF ' . $this->name );
}   /* End of QuitusModule.browse() */        

OK ... the browse is behind our back. We now need to do the same sort of thing but for the form.

QuitusModule : __toForm()

The __toForm() method is pretty much like the Browse() method:

/* ==================================================== */
/** {{*__toForm()=

     Presents an HTML form to create/modify entries related tothe current module

    {*params
    *}

    {*return
        (string)        HTML code of the form
    *}


    {*seealso
        @fnc.run, @fnc.browse
    *}

    {*warning
        This is the first step in using a "Quitus" module. The code is therefore
        not stable and not finished (it doesn't cover everything a Quitus module
        should).
    *}

    {*example
    *}

    *}}
*/
/* ==================================================== */
public function __toForm() : string
{
  $retVal = 'I AM THE FORM OF ' . $this->name;

  // If we have a parent suite
  if ( ! empty( $this->parentSuite ) )
  {
    // If there is an illicoDB associated to the parent suite
    if ( ! empty( $this->parentSuite->IllicoDB ) )
    {
      //echo "<p>MAYBE THERE IS A BROWSE IN THE ILLICODB3 PROPERTY OF THE PARENT SUITE</p>";
      // If we can open the main DB
      if ( $success = $this->parentSuite->IllicoDB->open( $this->parentSuite->IllicoDB->name ) )
      {
        // This is supposed to be the main table of the module
        $mainTable = $this->tables[0];

        //echo "<p>LA DB EST OUVERTE; JE DOIS OUVRIR LA TABLE PRINCIPALE {$mainTable}</p>";

        // If we can find the main table in the DB
        if ( $table = $this->parentSuite->IllicoDB->$mainTable )
        {
          //echo "<p>LA TABLE PRINCIPALE {$mainTable} EST OK</p>";
          // Return a FORM based on IllicoDB3
          $retVal = $table->__toForm();
        }   /* if ( $table = $this->parentSuite->IllicoDB->$mainTable ) */
      }
      else
      {
        echo "<p>LA DB N'EST PAS OUVERTE</p>";
      }
    }   /* if ( ! empty( $this->parentSuite->IllicoDB ) ) */
  }   /* if ( ! empty( $this->parentSuite ) ) */

  return ( $retVal );
}   /* End of QuitusModule.__toForm() */        

Here's the global result of what was programmed today:


The Browse


The result of __toForm()

Conclusion

We have succeeded presenting our four modules in a sort of main menu. We have succeeded also in the presenting of a specific module, even though the only module that we checked (part of our daily assignment) is the CliFou module.

We also succeeded making the link between a Quitus Suite, a Quitus Module and an instance of IllicoDB3. Having this link available made it possible in turn to call upon the intelligence that was programmed by AI (Sermo ... our entry door to ChatGPT), the browse() method of an IllicoDB3 table.

The same kind of thing authorized us to call the __toForm() method.

Cart full, folks. We have an ugly module that displays its data and lets you enter new data. These are NOT yet saved, however (we've still got some way to go on that one). However, what we have here is already quite astonishing for... only 2 days of programming.

Code included in the article (link to https://www.trql.fm/test.quitus.code-of-article4.zip) : test.quitus.code-of-article4.zip (we use the code of the next article ! :-))

Previous article - Next article


















Mira Savchenko

Document Solutions Specialist at Nectain

2 个月

impressive progress! seamless integration breeds innovation.

回复

要查看或添加评论,请登录

社区洞察

其他会员也浏览了