xaseTabs – extensible jQuery Tab Plugin

About a year ago, I created a jQuery Plugin to add tab-functionality to your page. The special thing about the plugin is, that is uses an event based approach. xaseTabs: xtensible and simple evented tabs. This enables you to extend the functionality of the plugin without altering the plugin-code. I have now published xasetabs.noelboss.ch where the options are documented and where you find extensions for the plugin.

How to create m:n relations with Extbase and Fluid

Update: don’t bother – I’ve found a much simpler solution and will update this tutorial soon! In the meantime, check out the extension on github where I’ve implemented the easy solution.

I was looking for a tutorial that explains how to create true m:n relational objects with Typo3 and Extbase and Fluid. Unfortunately I could not find something that explained how I could get this to work with the Extension Builder. I finally figured out a working solution. This post will be a short tutorial on how to accomplish „has many and is child of many“ relations with the Extbase Extension Builder.

  • First you need Extbase and Fluid installed – it comes bundled with Typo3 – I used Typo3 4.5.3 with Extbase and Fluid 1.3
  • You also need to download and install the Extension Builder –  unfortunately it’s not in the TER at the moment

This tutorial will show you, how to create an extension with an object „category“ which can have subcategories of the same type. You can create Categories and Subcategories. You can also assign multiple parent categories to subcategories and so forth. The relation will be visible on both ends.

First, you need to create a new extension. Switch to the Extension Builder and enter some details for your extension. In my case I create a new extension nbomn :

Hit „save“ after you have created the basics.

Now we are going to create a new Model „Category“. It is of the type „Entity“ which is an object that has a unique identity. Much like a car – compared to a value object which would be more like a color that only has a meaning when applied to a subject (car) but can’t stand for it’s own. It’s also an aggregate root – this means the extension builder will generate a repository and default controller actions for this model so we can easily fetch and save objects – this has nothing to do with the m:n relation.

Now that we have created the Model, let us add some properties. First and most obvious, we need a name for the category – this is of the type „String“, and it’s also required. Second, we need a new field that acts as the counterpart for the m:n relations. The Extension Builder will not create this automatically. It is of the type „Integer“ and not required (since not all categories have parents).

Last but very much not least, we create a relation of the object to itself. The name of the relations is „subcategory“ and it is of the type „m:n“ – since this is what it’s all about. Also, we don’t want it to be a „inline“ relation – we could not select existing categories that way. Then, we connect the „dot“ from the relation to the dot of the domain by dragging a line from the dot at the bottom to the dot at the top left.

You will end up with this (Properties folded):

Now you can save your extension. You have now a new folder named after your extension key in your extension folder typo3conf/ext/yourextkey. We now have to update two things:

  1. The MySQL database scheme for our mm table
  2. The TCA configuration for the Typo3 backend forms

Open the file „ext_tables.sql“ and scroll down to your mm table. We will need to add three fields and change the KEY fields:

  1. New field uid
  2. New field pid
  3. New field tablenames

We will also change the KEY definition and define the UID as the PRIMARY KEY and the pid as the parent KEY.

## Original fields:
# KEY uid_local (uid_local),
# KEY uid_foreign (uid_foreign)

## Changed fields for m:n
PRIMARY KEY (uid),
KEY parent (pid),

## New Fields for m:n
uid int(10) NOT NULL auto_increment,
pid int(11) DEFAULT '0' NOT NULL,
tablenames varchar(255) DEFAULT '' NOT NULL

Now we change the subcategory TCA definition to allow for true m:n relations. Open the file „Category.php“ at „Configuration/TCA“ and find „MM“ inside the „subcategory“ configuration. We add two new definitions:

  1. „MM_match_fields“ that matches the „tablenames“ field from the mm table. Don’t forget to adjust it to your correct field-names!
  2. „MM_opposite_field“ that links to our „category_mm“
'MM_match_fields' => array(
      'tablenames' => 'tx_nbomn_domain_model_category'   
),
'MM_opposite_field' => 'category_mm',

You should also add a line inside the „add wizard“ configuration to prevent adding new subcategories before the parent has been saved:

'notNewRecords' => 1,

That’s it for the subcategory configuration. It can now store relations to other categories. Now we need to setup the parent categories. We replace the whole „config“ array of the „category_mm“ field with the one of „subcategory“. Then we remove the „MM_opposite_field“ entry:

That’s all. Now we have working Sub- and Parentcategories. You can now go to the Extension Manager and install your Extension. Then create a Sysfolder somewhere in your Pagetree and insert a new category.

After you save the category, you can create subcategories and also add new parent categories:

I hope, this helped you to create your own m:n relations with the Extbase Extension Builder. If you have any questions or suggestions, feel free to leave a comment. In case you like to take a look at my test extension – download nbomn – it’s also on GitHub.

Ps. On my way to this solution this thread was useful.

htmldecode and encode View Helpers for Fluid (Update)

Fluid and Extbase are cool stuff! Really. Right now I create a new extension for a Namics customer and I am also working on a port of my podcast extension. All the basic stuff is already done; creating xml, rendering views for the podcasts including HTML5 Audio output etc. – if you like to offer help, leave me a comment.
One thing I found laking was, that objects assigned to the view are html encoded – this means, that if you assign the view a prerendered tag, lets say a captcha-image, it will show up as text and not as html tag. There is no easy way around it – that said, if you’re not up to abuse the helper by providing a wrong parseFuncTSPath argument. That’s why I have written two simple fluid view helpers that might help you with your own extension:

htmlDecode View Helper

class Tx_YourExtensionKey_Format_HtmlDecodeViewHelper extends Tx_Fluid_Core_ViewHelper_AbstractViewHelper {
    /**
     * Decodes a given string to HTML
     *
     * @param string $string the string to be decoded
     * @param string $quote_style The optional second quote_style parameter lets you define what will be done with 'single' and "double" quotes. It takes on one of three constants with the default being ENT_COMPAT:
     * @param string $charset The URF-8 character set is used as default for the optional third charset. This defines the character set used in conversion.
     * @return string htmldecoded string
     * @author Noel Bossart 
     */
    public function render($code = NULL, $quote_style = ENT_COMPAT, $charset = 'UTF-8') {
        if ($code === NULL) {
            $code = $this->renderChildren();
        }
        return html_entity_decode($code, $quote_style, $charset);
    }
}

htmlEncode View Helper:

class Tx_YourExtensionKey_ViewHelpers_Format_HtmlEncodeViewHelper extends Tx_Fluid_Core_ViewHelper_AbstractViewHelper {

    /**
     * HTML encodes a given string
     *
     * @param string $string the string to be encoded
     * @param string $quote_style The optional second quote_style parameter lets you define what will be done with 'single' and "double" quotes. It takes on one of three constants with the default being ENT_COMPAT:
     * @param string $charset The URF-8 character set is used as default for the optional third charset. This defines the character set used in conversion.
     * @return string HTML encoded string
     * @author Noel Bossart
     */
    public function render($code = NULL, $quote_style = ENT_COMPAT, $charset = 'UTF-8') {
        if ($code === NULL) {
            $code = $this->renderChildren();
        }
        return htmlspecialchars($code, $quote_style, $charset);
    }
}

You can download both view helpers and put the files into the following folder: EXT:/yourextension/Classes/ViewHelpers/Format/

Updated: Or you just use html_entity_decode() before you pass it to the view :)