In this tutorial we are going to learn to create new functionalities on our TYPO3 project by using the MVC framework TYPO3 ships with. MVC stands for Model View Controller. We gonna learn how the MVC works during this tutorial as well. Let us start!
*NOTE: First create a new file in Classes/Domain/Model [Product.php].
Open [Product.php]
<?php namespace Contencance\YoutubeDemo\Domain\Model; use TYPO3\CMS\Extbase\DomainObject\AbstractEntity; class Product extends AbstractEntity { /** * The name of the product * * @var string **/ protected $name = ''; /** * The description of the product * * @var string **/ protected $description = ''; /** * The quantity in the store inventory * * @var int **/ protected $quantity = 0; /** * Product constructor. * * @param string $name * @param string $description * @param int $quantity */ public function __construct($name = '', $description = '', $quantity = 0) { $this->setName($name); $this->setDescription($description); $this->setQuantity($quantity); } /** * Sets the name of the product * * @param string $name */ public function setName(string $name) { $this->name = $name; } /** * Gets the name of the product * * @return string */ public function getName() { return $this->name; } /** * Sets the description of the product * * @param string $description */ public function setDescription(string $description) { $this->description = $description; } /** * Gets the description of the product * * @return string */ public function getDescription() { return $this->description; } /** * Sets the quantity in the store inventory of the product * * @param int $quantity */ public function setQuantity(int $quantity) { $this->quantity = $quantity; } /** * Gets the quantity in the store inventory of the product * * @return int */ public function getQuantity() { return $this->quantity; } }
Model stands for the first 'M' in MVC. This class creates a model of a database table. This class will hold every fields from database as properties. It will also have getters and setters to modify its value as well a the contructor. By using this class we can modify directly a database entry without touching sql code.
We have created the model but no real database yet, so lets begin!
Open [ext_tables.sql]
CREATE TABLE tx_youtubedemo_domain_model_product ( uid int(11) unsigned DEFAULT '0' NOT NULL auto_increment, pid int(11) DEFAULT '0' NOT NULL, name varchar(255) DEFAULT '' NOT NULL, description text NOT NULL, quantity int(11) DEFAULT '0' NOT NULL, PRIMARY KEY (uid), KEY parent (pid) );
*IMPORTANT: There is a specific way to name tables so it know which model to use.
tx_youtubedemo_domain_model_product is the table name from which you start with "tx" then extesion name mine is "youtubedemo" after is path to model "domain" and "model" and finaly the name of model "product" in my case. All should be lower case and without special characters. The "_" is reserved as a special character to divide these components if your extension has a name with "_" symbol that write it without this.
Now that the table is created we should Analyze the Database and update it. After this let us configure this table in TCA. Create a php file with the name of the table in Configuration/TCA
Open [tx_youtubedemo_domain_model_product.php]
<?php return [ 'ctrl' => [ 'title' => 'Product', 'label' => 'name', 'iconfile' => 'EXT:youtube_demo/Resources/Public/Icons/cat.svg' ], 'columns' => [ 'name' => [ 'label' => 'Name', 'config' => [ 'type' => 'input', 'size' => '20', 'eval' => 'trim' ], ], 'description' => [ 'label' => 'Description', 'config' => [ 'type' => 'text', 'eval' => 'trim' ], ], 'quantity' => [ 'label' => 'Quantity', 'config' => [ 'type' => 'input', 'size' => '4', 'eval' => 'int' ], ], ], 'types' => [ '0' => ['showitem' => 'name, description, quantity'], ], ];
Now let us Create a Folder called Data in Page tree and inside this another folder called Product enable both of them.
Let us open Product in List mode and add some records in it
After this click on Product in the end. I have it with a cat icon you can modify that in [tx_youtubedemo_domain_model_product.php]
Fill the fields and if we check now the folder of Product it is added there. Also in database as well.
Before we do anything else, we should create a repository in "Classes/Domain/Repository". The repository uses the model and creates for a us a nice couple of functions which we can use to update the database or get data from database. All this without using sql.
*IMPORTANT: There is a specific naming convetion to be followed as described below.
Repository name is: Name of the model with Repository attached to in both with capital first letters. In my example that is ProductRepository
Open [ProductRepository.php]
<?php namespace Contencance\YoutubeDemo\Domain\Repository; use TYPO3\CMS\Extbase\Persistence\Repository; /** * Class ProductRepository */ class ProductRepository extends Repository { }
Don't worry because it is empty it already is inheriting all the method we need from the Repository class
After this it is time to create the Controller in "Classes/Controller" a controller called [StoreInventoryController.php]
Open [StoreInventoryController.php]
<?php namespace Contencance\YoutubeDemo\Controller; use Contencance\YoutubeDemo\Domain\Repository\ProductRepository; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; /** * Class StoreInventoryController * * @package MyVendor\StoreInventory\Controller */ class StoreInventoryController extends ActionController { /** * @var ProductRepository */ private $productRepository; /** * Inject the product repository * * @param \MyVendor\StoreInventory\Domain\Repository\ProductRepository $productRepository */ public function injectProductRepository(ProductRepository $productRepository) { $this->productRepository = $productRepository; } /** * list Action * * @return void */ public function listAction() { $products = $this->productRepository->findAll(); $this->view->assign('products', $products); } }
*Recap
Controller act as a middleman controlling the flow of information from Model/Repository to View. Model has the database table model and the fields and methods for getters and setters. Repository based on the model it extends it functionality by offering us some neat methods like 'findAll()' we have used in 'listAction()' in controller. After we get the results we add them to products variable and then return them to the view in which we can display them as we like.
Now it is time for the frontend. First we create a folder in template. The folder should have the Controller name without the 'Controller', for me it is "StoreInventory". Inside this folder create a new html file based on the method name without the 'Action' with capital first letter, for me it is [List.html]
Open [List.html]
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"> <table border="1" cellspacing="1" cellpadding="5"> <tr> <td>Product name</td> <td>Product description</td> <td>Quantity</td> </tr> <f:for each="{products}" as="product"> <tr> <td align="top">{product.name}</td> <td align="top"> <f:format.crop maxCharacters="100">{product.description}</f:format.crop> </td> <td align="top">{product.quantity}</td> </tr> </f:for> </table> </html>
Now the final touches let us register the plugin:
Open [tt_content.php]
<?php defined('TYPO3') or die('Access denied.'); \TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin( 'youtube_demo', 'InventoryList', 'The Store Inventory List', 'EXT:youtube_demo/Resources/Public/Icons/cat.svg' );
Also let us configured it:
Open [ext_localconf.php]
<?php defined('TYPO3') or die('Access denied.'); use TYPO3\CMS\Extbase\Utility\ExtensionUtility; use Contencance\YoutubeDemo\Controller\StoreInventoryController; /*************** * Custom PLugins */ ExtensionUtility::configurePlugin( 'youtube_demo', 'InventoryList', [StoreInventoryController::class => 'list',], [StoreInventoryController::class => '',], );
Go to the page we want our plugin
As always you can now try to experiment with it. We can add other methods to controller. As we saw the controller acts as a middle man by using the database model to get all the records from the table using methods from repository and returning a view in the template. See you in other tutorials.