Contao - Using a frontend module in another module | qzminski Blog

Using a frontend module in another module

It’s been a while since my last post, but haven’t got inspiration to write new ones. I have recently started a new big project in Contao, so I will share my latest revelations about development in this CMS. In this post I will show you how to use code from module1 in module2, without writing it again.

The DRY (Don’t Repeat Yourself) principle is the one you should take as the main rule while developing. It might split your project into several parts, but therefore you can use any module anywhere. One of the biggest advantage is that you don’t have to modify the same code in several places, but only in one.

Let’s imagine situation where we have News module and Gallery module. You would like to display the comments under both of them. Normally, you would write two almost identical codes in each of these modules:

$objComment = $this->Database->prepare("SELECT * FROM tl_comments WHERE pid=?")->execute($intId);

while ($objComment->next())
{
  $arrComments[] = array
  (
    'date'   => date('j M Y', $objComment->tstamp),
    'author' => $objComment->author,
    'text'   => $objComment->text
  );
}

$this->Template->comments = $arrComments;

Then you would use foreach() loop in the News and Gallery templates and comments would appear. This is okay, but it’s against the DRY principle.

Now imagine, somewhen in the future you want to quickly display an additional field from the database. You’d have to modify code in both modules, plus the both templates.

Whereas modifying two modules is not a big deal, more of them could be a problem.

How to avoid this?

Avoiding this is quite simple, the solution is used in e.g. Contao’s News module. We need to write a function that will be shared by both modules. Here’s how to do it.

There are basically two ways of sharing a function.

First – News and Gallery will extend the same class. Take a look:

class ModuleNews extends ModuleParent
{
  // ...
}

class ModuleGallery extends ModuleParent
{
  // ...
}

I use this way because it provides me additional possibilites, like doing most of each modules logic in parent’s one function.

The second way is you can use is:

class ModuleNews extends Module
{
  $this->import('Comments');
  $this->Comments->parseComments();
}

class Comments extends Module
{
  // ...
}

To be honest, I haven’t tested this method, but according to this post it should work.

Parse comments

I will describe the first method, however the logic remains the same, so you should be able to use this code also in second method.

First of all we need to create a function, that will parse the comments and return them as an array:

class ModuleParent extends Module
{
  protected function parseComments(Database_Result $objComments)
  {
    if ($objComments->numRows < 1)
    (
      return array();
    )

    $arrComments = array();

    while ($objComments->next())
    {
      $objTemplate = new FrontendTemplate('com_default');

      $objTemplate->date = date('j M Y', $objComment->tstamp);
      $objTemplate->author = $objComment->author;
      $objTemplate->text = $objComment->text;

      $arrComments[] = $objTemplate->parse();
    }

    return $arrComments;
  }
}

Okay, let me explain it a lil bit.

Line 3 – as the first and the only parameter we take the database object that holds comments. We could also provide a second parameter, which would tell what’s the name of the template for comments.

Line 5 to 8 – in case there are no comments in the database, we return an empty array. This will prevent our module from throwing an error.

Line 10 – same as before, we prevent from throwing an error.

Line 14 – we instantiate a new frontend template that will display our comments. In this case we call com_default to life.

Line 16 to 18 - this is self explanatory, we add the data to our template file.

Line 20 – we parse all of the templates, e.g. if there are 3 comments, the template will be parsed 3 times (each time with different data).

Okay, we’ve got main function finished, now it’s time to see how we can use it.

We need to pass a database result to our function, so in News module we run a query:

// $intId = news item id
$objComment = $this->Database->prepare("SELECT * FROM tl_comments WHERE pid=?")->execute($intId);
$this->Template->comments = $this->parseComments($objComment);

And that’s it! We fetched all comments that are belong to a single news item, parsed them and assigned to the template.

To display them, in your News module template put the following code:

<?php foreach($this->comments as $comment) echo $comment; ?>

In the place of foreach() loop we will see the comments. Each comment will be put into its template file, so if you got

<div class="comment">
  <strong><?php echo $this->author; ?></strong> on <?php echo $this->date; ?>
  <p><?php echo $this->text; ?></p>
</div>

in your com_default, this code will be displayed n times when there are n comments.


About Author

Kamil Kuzminski

Hi! I'm a webdeveloper from Olsztyn, Poland. I'm the manager of Contao (fka TYPOlight) polish support website and community. I work mainly as a freelancer for private clients or various agencies.





Comments

  1. Brian June 23rd

    Comment Arrow

    Thanks for another great post, man. Keep up the good work.


  2. Phillip August 8th

    Comment Arrow

    Where would I be without your posts! Thanks a lot for taking the time to write them, this is an invaluable source of information.


Add Yours

  • Author Avatar

    YOU


Comment Arrow