J3.x

Developing an MVC Component/Adding a Feed

From Joomla! Documentation

< J3.x:Developing an MVC Component
Other languages:
English • ‎français • ‎italiano • ‎中文(台灣)‎
Joomla! 
3.x
Tutorial
Developing an MVC Component



This is a multiple-article series of tutorials on how to develop a Model-View-Controller Component for Joomla! VersionJoomla 3.x.

Begin with the Introduction, and navigate the articles in this series by using the navigation button at the bottom or the box to the right (the Articles in this series).



This tutorial is part of the Developing an MVC Component for Joomla! 3.2 tutorial. You are encouraged to read the previous parts of the tutorial before reading this.

In this step we add a feed to our component. A video accompanying this tutorial may be found at Adding a Feed.

Introduction[edit]

If you're not familiar with feeds then it's worth doing some background reading on the Internet. Joomla provides the capability of generating a feed of featured articles, or articles in a category – see for example this tutorial. In this tutorial step we enable equivalent functionality for generating a feed of helloworld records associated with a helloworld category.

On the Joomla website setting up a feed associated with an article category involves

  1. creating a menuitem pointing to a webpage showing articles in a given category
  2. enabling the Syndication Feed module and displaying it on that menuitem.

This module displays an RSS symbol on the webpage which has behind it a link to the URL of the RSS or Atom feed associated with that article category.

To subscribe to the feed a user copies this URL into his or her feed aggregator. When the feed aggregator sends an HTTP request to this URL, then the Joomla website returns an XML document containing details of the articles in that category – their titles, descriptions, published dates, etc.

So for example, if the webpage displays a list of the articles associated with a category "technology" then the URL behind the RSS image will point to the associated feed. When a browser or feed aggregator sends an HTTP request to that feed URL then the server will return an XML document in RSS or Atom format containing details of those articles with a category of "technology".

In this way a feed aggregator can send HTTP requests to all of the feeds to which the user has subscribed, and collate them so that user doesn't have to visit each of the individual news websites. And the user can configure the news aggregator to check the feeds at specific times, so that the information can been already collected and collated by the time the user wishes to view it.

Note that in addition to the syndicated feed which we're considering here, Joomla also has a newsfeed capability, which enables you to display a webpage showing information collected from syndicated feeds elsewhere – similar to what a feed aggregator would do – but this isn't the functionality which this tutorial step is about.


Approach[edit]

We currently have a site category view which displays the helloworld records associated with a given category. In this step we add an RSS syndicated feed to this page. This will result in an RSS symbol shown as an image, with a URL behind which will give an XML feed in RSS or Atom format of the helloworld records associated with that category.

If you haven't already got a site menuitem which points to a category view then you should configure one as a starting point.

To enable the syndicated feed we must do the following.

  1. Under Modules, find and enable the Syndicated Feed module. Click on this module to edit its options, and under the Menu Assignment tab ensure that it's shown just on the site page which displays the helloworld category view. Note that among the options there is one which defines whether Joomla presents the XML data in the RSS or Atom format.
  2. Define a helloworld configuration parameter which controls whether the RSS symbol with its link is shown or not. The Joomla code displays the RSS symbol only if it finds this parameter and it's set to Show.
  3. In the category view.html.php we need to inherit from JViewCategory (which in the revised namespacing scheme is CategoryView in namespace Joomla\CMS\MVC\View) and call the addFeed() method of this class. This method inserts the RSS/Atom links into the document <head> – which is where the Syndicated Feed module expects to find the URL for putting behind the RSS symbol.
  4. The URL for the RSS feed includes the query parameter "format=feed" so we need to have a file view.feed.php and the code for this new file is found below. Note that it inherits from the class JViewCategoryfeed, or in the newer namespaced structure CategoryFeedView within the namespace Joomla\CMS\MVC\View.
  5. Include in the SQL query within the helloworld category model all the fields which you want to populate within the RSS/Atom feed XML document.

The URL of the RSS feed will be something like: http://yourDomain.com/yourJoomlaInstance/index.php?option=com_helloworld&view=category&id=37&Itemid=822&lang=en&format=feed&type=rss When Joomla receives a URL like this, it handles it in the same way as usual:

  • the option is "com_helloworld", so it will run our helloworld.php file
  • it will run the display() method within the helloworld controller – this will as usual set up the view and the model
  • because the URL parameter format = "feed" it will expect the view to be in ./views/category/view.feed.html and will run the HelloworldViewCategory::display() method.
  • this display() code is found from the parent class JViewCategoryfeed / CategoryFeedView. This is the code which brings together the data to be put into the response XML document – for example, the titles, descriptions, links – mapping them from the fields in the SQL query result, and I would recommend looking through the code to get an idea of what it does.
    • it calls $this->get('Items'), which gets translated into a call getItems() in the model – so we need to ensure that our SQL query in this function provides all the fields we want to be present in the RSS XML response.
    • it calls $this->get('Category'), so we need to have a method getCategory() in our model
    • it maps some of the fields using the ucm content-types field mapping data which we supplied in the step Adding Tags. To find the correct record in this table it uses the key formed by the extension ("com_helloworld") and the view ("helloworld"), so this is why we need to set the $viewname property in this class.
    • it allows us to define mappings of other fields through the method reconcileNames(). We use this to include in the description field a link to the associated image.

Configuration changes[edit]

Following standard Joomla practice, we put the Show Feed Link option within the integration tab of the Helloworld configuration options.

admin/config.xml

<?xml version="1.0" encoding="utf-8"?>
<config>
	<fieldset
		name="greetings"
		label="COM_HELLOWORLD_CONFIG_GREETING_SETTINGS_LABEL"
		description="COM_HELLOWORLD_CONFIG_GREETING_SETTINGS_DESC"
	>
		<field
			name="show_category"
			type="radio"
			label="COM_HELLOWORLD_HELLOWORLD_FIELD_SHOW_CATEGORY_LABEL"
			description="COM_HELLOWORLD_HELLOWORLD_FIELD_SHOW_CATEGORY_DESC"
			default="0"
		>
			<option value="0">JHIDE</option>
			<option value="1">JSHOW</option>
		</field>
        <field
			name="captcha"
			type="plugins"
            folder="captcha"
			label="COM_HELLOWORLD_HELLOWORLD_FIELD_CAPTCHA_LABEL"
			description="COM_HELLOWORLD_HELLOWORLD_FIELD_CAPTCHA_DESC"
			default="0"
			filter="cmd"
		>
            <option value="">JOPTION_USE_DEFAULT</option>
			<option value="0">JOPTION_DO_NOT_USE</option>
		</field>
        <field
			name="user_to_email"
			type="user"
			label="COM_HELLOWORLD_HELLOWORLD_FIELD_USER_TO_EMAIL_LABEL"
			description="COM_HELLOWORLD_HELLOWORLD_FIELD_USER_TO_EMAIL_DESC"
			default="0"
		>
		</field>
		<field
			name="save_history"
			type="radio"
			class="btn-group btn-group-yesno"
			default="1"
			label="JGLOBAL_SAVE_HISTORY_OPTIONS_LABEL"
			description="JGLOBAL_SAVE_HISTORY_OPTIONS_DESC"
		>
			<option
				value="0">JNO</option>
			<option
				value="1">JYES</option>
		</field>
		<field
			name="history_limit"
			type="text"
			filter="integer"
			label="JGLOBAL_HISTORY_LIMIT_OPTIONS_LABEL"
			description="JGLOBAL_HISTORY_LIMIT_OPTIONS_DESC"
			default="5"
		>
		</field>
	</fieldset>
	<fieldset name="integration"
		label="JGLOBAL_INTEGRATION_LABEL"
		description="COM_HELLOWORLD_CONFIG_INTEGRATION_SETTINGS_DESC"
	>
		<field
			name="show_feed_link"
			type="radio"
			class="btn-group btn-group-yesno"
			default="1"
			label="JGLOBAL_SHOW_FEED_LINK_LABEL"
			description="JGLOBAL_SHOW_FEED_LINK_DESC">
			<option value="1">JSHOW</option>
			<option value="0">JHIDE</option>
		</field>
	</fieldset>
    <fieldset
		name="permissions"
		label="JCONFIG_PERMISSIONS_LABEL"
		description="JCONFIG_PERMISSIONS_DESC"
	>
		<field
			name="rules"
			type="rules"
			label="JCONFIG_PERMISSIONS_LABEL"
			class="inputbox"
			validate="rules"
			filter="rules"
			component="com_helloworld"
			section="component"
		/>
	</fieldset>
</config>

Category View code files[edit]

In our updated category view html file we change the class we're inheriting from and include a call to the parent addFeed() method. This method expects the params to have been set.

site/views/category/view.html.php

<?php
/*
 * View file for the view which displays a list of helloworld messages in a given category
 */
 
defined('_JEXEC') or die;

class HelloworldViewCategory extends JViewCategory
{
	public function display($tpl = null)
	{
		$this->categoryName = $this->get("CategoryName");

		$this->items = $this->get('Items');
		$this->pagination = $this->get('Pagination');
		$this->state = $this->get('State');
		$this->filterForm    	= $this->get('FilterForm');
		$this->activeFilters 	= $this->get('ActiveFilters');

		$this->subcategories = $this->get('Subcategories');

		$this->params = JFactory::getApplication()->getParams();

		parent::display($tpl);
	}

	protected function prepareDocument()
	{
		parent::prepareDocument();
		parent::addFeed();
	}
}

We also have the new view file for the feed format.

site/views/category/view.feed.php

<?php
/**
 * view file associated with the Syndicated Feed for a helloworld category
 */

defined('_JEXEC') or die;

class HelloworldViewCategory extends JViewCategoryfeed
{
	// required so that the parent class can find the helloworld content-type record containing the field mapping details
	protected $viewName = 'helloworld';

	/**
	 * Function overriding the parent reconcileNames() method. 
	 * We use this to insert an html link to the helloworld image into the description
	 * 
	 * The input parameter is the helloworld item as extracted from the database, passed by reference
	 *
	 * The result of the method is that the helloworld item passed as a parameter gets its description property changed
	 */
	protected function reconcileNames($item)
	{ 
		$description = '';
		
		if (!empty($item->image))
		{
			// Convert the JSON-encoded image info into an array
			$imageDetails = new JRegistry;
			$imageDetails->loadString($item->image, 'JSON');
			$src = $imageDetails->get('image','');
			if (!empty($src))
			{
				$description .= '<p><img src="' . $src . '" /></p>';
			}
		}
		$item->description =  $description . $item->description;
	}
}

Model changes[edit]

site/models/category.php

<?php
/**
 * Model for displaying the helloworld messages in a given category
 */

defined('_JEXEC') or die;

class HelloworldModelCategory extends JModelList
{
	public function __construct($config = array())
	{
		if (empty($config['filter_fields']))
		{
			$config['filter_fields'] = array(
				'id',
				'greeting',
				'alias',
				'lft',
			);
		}

		parent::__construct($config);
	}
    
	protected function populateState($ordering = null, $direction = null)
	{
		parent::populateState($ordering, $direction);
        
		$app = JFactory::getApplication('site');
		$catid = $app->input->getInt('id');

		$this->setState('category.id', $catid);
	}
    
	protected function getListQuery()
	{
		$db    = JFactory::getDbo();
		$query = $db->getQuery(true);

		$catid = $this->getState('category.id'); 
		$query->select('id, greeting, alias, catid, access, description, image')
			->from($db->quoteName('#__helloworld'))
			->where('catid = ' . $catid);

		if (JLanguageMultilang::isEnabled())
		{
			$lang = JFactory::getLanguage()->getTag();
			$query->where('language IN ("*","' . $lang . '")');
		}

		$orderCol	= $this->state->get('list.ordering', 'lft');
		$orderDirn 	= $this->state->get('list.direction', 'asc');

		$query->order($db->escape($orderCol) . ' ' . $db->escape($orderDirn));

		return $query;	
	}

	public function getCategoryName()
	{
		$catid = $this->getState('category.id'); 
		$categories = JCategories::getInstance('Helloworld', array('access' => false));
		$categoryNode = $categories->get($catid);   
		return $categoryNode->title; 
	}
    
	public function getSubcategories()
	{
		$catid = $this->getState('category.id'); 
		$categories = JCategories::getInstance('Helloworld', array('access' => false));
		$categoryNode = $categories->get($catid);
		$subcats = $categoryNode->getChildren(); 
        
		$lang = JFactory::getLanguage()->getTag();
		if (JLanguageMultilang::isEnabled() && $lang)
		{
			$query_lang = "&lang={$lang}";
		}
		else
		{
			$query_lang = '';
		}
        
		foreach ($subcats as $subcat)
		{
			$subcat->url = JRoute::_("index.php?view=category&id=" . $subcat->id . $query_lang);
		}
		return $subcats;
	}

	public function getCategoryAccess()
	{
		$catid = $this->getState('category.id'); 
		$categories = JCategories::getInstance('Helloworld', array('access' => false));
		$categoryNode = $categories->get($catid);   
		return $categoryNode->access; 
	}
	
	public function getItems()
	{
		$items = parent::getItems();
		$user = JFactory::getUser();
		$loggedIn = $user->get('guest') != 1;

		if ($user->authorise('core.admin')) // ie superuser
		{
			return $items;
		}
		else
		{
			$userAccessLevels = $user->getAuthorisedViewLevels();
			$catAccess = $this->getCategoryAccess();
			
			if (!in_array($catAccess, $userAccessLevels))
			{  // the user hasn't access to the category
				if ($loggedIn)
				{	
					return array();
				}
				else
				{
					foreach ($items as $item)
					{
						$item->canAccess = false;
					}
					return $items;
				}
			}

			foreach ($items as $item) 
			{
				if (!in_array($item->access, $userAccessLevels))
				{
					if ($loggedIn)
					{
						unset($item);
					}
					else
					{
						$item->canAccess = false;
					}
				}
			}
		}
		return $items;
	}

	public function getCategory()
	{
		$categories = JCategories::getInstance('Helloworld', array());
		$category = $categories->get($this->getState('category.id', 'root'));
		return $category;
	}
}

Updated Language Strings[edit]

admin/language/en-GB/en-GB.com_helloworld.ini

; Joomla! Project
; Copyright (C) 2005 - 2018 Open Source Matters. All rights reserved.
; License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php
; Note : All ini files need to be saved as UTF-8

COM_HELLOWORLD_ADMINISTRATION="HelloWorld - Administration"
COM_HELLOWORLD_ADMINISTRATION_CATEGORIES="HelloWorld - Categories"
COM_HELLOWORLD_NUM="#"
COM_HELLOWORLD_HELLOWORLDS_FILTER="Filters"
COM_HELLOWORLD_AUTHOR="Author"
COM_HELLOWORLD_LANGUAGE="Language"
COM_HELLOWORLD_CREATED_DATE="Created"
COM_HELLOWORLD_PUBLISHED="Published"
COM_HELLOWORLD_HELLOWORLDS_NAME="Name"
COM_HELLOWORLD_HELLOWORLDS_POSITION="Position"
COM_HELLOWORLD_HELLOWORLDS_IMAGE="Image"
COM_HELLOWORLD_HELLOWORLDS_ASSOCIATIONS="Associations"
COM_HELLOWORLD_ID="Id"

COM_HELLOWORLD_HELLOWORLD_CREATING="HelloWorld - Creating"
COM_HELLOWORLD_HELLOWORLD_DETAILS="Details"
COM_HELLOWORLD_HELLOWORLD_EDITING="HelloWorld - Editing"
COM_HELLOWORLD_HELLOWORLD_ERROR_UNACCEPTABLE="Some values are unacceptable"
COM_HELLOWORLD_HELLOWORLD_FIELD_CATID_DESC="The category the messages belongs to"
COM_HELLOWORLD_HELLOWORLD_FIELD_CATID_LABEL="Category"
COM_HELLOWORLD_HELLOWORLD_FIELD_GREETING_DESC="This message will be displayed"
COM_HELLOWORLD_HELLOWORLD_FIELD_GREETING_LABEL="Message"
COM_HELLOWORLD_HELLOWORLD_FIELD_DESCRIPTION_DESC="Message description"
COM_HELLOWORLD_HELLOWORLD_FIELD_DESCRIPTION_LABEL="Description"
COM_HELLOWORLD_HELLOWORLD_FIELD_SHOW_CATEGORY_LABEL="Show category"
COM_HELLOWORLD_HELLOWORLD_FIELD_SHOW_CATEGORY_DESC="If set to Show, the title of the message&rsquo;s category will show."
COM_HELLOWORLD_HELLOWORLD_FIELD_LATITUDE_LABEL="Latitude"
COM_HELLOWORLD_HELLOWORLD_FIELD_LATITUDE_DESC="Enter the position latitude, between -90 and +90 degrees"
COM_HELLOWORLD_HELLOWORLD_FIELD_LONGITUDE_LABEL="Longitude"
COM_HELLOWORLD_HELLOWORLD_FIELD_LONGITUDE_DESC="Enter the position longitude, between -180 and +180 degrees"
COM_HELLOWORLD_HELLOWORLD_FIELD_PARENT_LABEL="Parent"
COM_HELLOWORLD_HELLOWORLD_FIELD_PARENT_DESC="Select the parent record"
COM_HELLOWORLD_ITEM_FIELD_ORDERING_VALUE_FIRST="-- First record"
COM_HELLOWORLD_ITEM_FIELD_ORDERING_VALUE_LAST="-- Last record"
COM_HELLOWORLD_ITEM_FIELD_ORDERING_TEXT="Ordering will be available after saving."
COM_HELLOWORLD_HELLOWORLD_FIELD_LANGUAGE_DESC="Select the appropriate language"
COM_HELLOWORLD_IMAGE_FIELDS="Image details"
COM_HELLOWORLD_HELLOWORLD_FIELD_IMAGE_LABEL="Select image"
COM_HELLOWORLD_HELLOWORLD_FIELD_IMAGE_DESC="Select an image from the library, or upload a new one"
COM_HELLOWORLD_HELLOWORLD_FIELD_ALT_LABEL="Alt text"
COM_HELLOWORLD_HELLOWORLD_FIELD_ALT_DESC="Alternative text (if image cannot be displayed)"
COM_HELLOWORLD_HELLOWORLD_FIELD_CAPTION_LABEL="Caption"
COM_HELLOWORLD_HELLOWORLD_FIELD_CAPTION_DESC="Provide a caption for the image"
COM_HELLOWORLD_HELLOWORLD_HEADING_GREETING="Greeting"
COM_HELLOWORLD_HELLOWORLD_HEADING_ID="Id"
COM_HELLOWORLD_MANAGER_HELLOWORLD_EDIT="HelloWorld manager: Edit Message"
COM_HELLOWORLD_MANAGER_HELLOWORLD_NEW="HelloWorld manager: New Message"
COM_HELLOWORLD_MANAGER_HELLOWORLDS="HelloWorld manager"
COM_HELLOWORLD_EDIT_HELLOWORLD="Edit message"
COM_HELLOWORLD_N_ITEMS_DELETED_1="One message deleted"
COM_HELLOWORLD_N_ITEMS_DELETED_MORE="%d messages deleted"
COM_HELLOWORLD_N_ITEMS_PUBLISHED="%d message(s) published"
COM_HELLOWORLD_N_ITEMS_UNPUBLISHED="%d message(s) unpublished"
COM_HELLOWORLD_HELLOWORLD_GREETING_LABEL="Greeting"
COM_HELLOWORLD_HELLOWORLD_GREETING_DESC="Add Hello World Greeting"
COM_HELLOWORLD_SUBMENU_MESSAGES="Messages"
COM_HELLOWORLD_SUBMENU_CATEGORIES="Categories"
COM_HELLOWORLD_CONFIGURATION="HelloWorld Configuration"
COM_HELLOWORLD_CONFIG_GREETING_SETTINGS_LABEL="Messages settings"
COM_HELLOWORLD_CONFIG_GREETING_SETTINGS_DESC="Settings that will be applied to all messages by default"
COM_HELLOWORLD_CONFIG_INTEGRATION_SETTINGS_DESC="Settings relating to integration with the Syndicated Feed module"
COM_HELLOWORLD_HELLOWORLD_FIELD_CAPTCHA_LABEL="Captcha"
COM_HELLOWORLD_HELLOWORLD_FIELD_CAPTCHA_DESC="Select Captcha to use on front end form"
COM_HELLOWORLD_HELLOWORLD_FIELD_USER_TO_EMAIL_LABEL="User to email"
COM_HELLOWORLD_HELLOWORLD_FIELD_USER_TO_EMAIL_DESC="Select user to email when a new message is entered on front end"
COM_HELLOWORLD_FIELDSET_RULES="Message Permissions"
COM_HELLOWORLD_FIELD_RULES_LABEL="Permissions"
COM_HELLOWORLD_ACCESS_DELETE_DESC="Is this group allowed to edit this message?"
COM_HELLOWORLD_ACCESS_DELETE_DESC="Is this group allowed to delete this message?"
COM_HELLOWORLD_TAB_NEW_MESSAGE="New Message"
COM_HELLOWORLD_TAB_EDIT_MESSAGE="Message Details"
COM_HELLOWORLD_TAB_PARAMS="Parameters"
COM_HELLOWORLD_TAB_ASSOCIATIONS="Associations"
COM_HELLOWORLD_TAB_PERMISSIONS="Permissions"
COM_HELLOWORLD_TAB_IMAGE="Image"
COM_HELLOWORLD_LEGEND_DETAILS="Message Details"
COM_HELLOWORLD_LEGEND_PARAMS="Message Parameters"
COM_HELLOWORLD_LEGEND_ASSOCIATIONS="Message Associations"
COM_HELLOWORLD_LEGEND_PERMISSIONS="Message Permissions"
COM_HELLOWORLD_LEGEND_IMAGE="Image info"
; Column ordering in the Helloworlds view
COM_HELLOWORLD_ORDERING_ASC="Ordering ascending"
COM_HELLOWORLD_ORDERING_DESC="Ordering descending"
COM_HELLOWORLD_GREETING_ASC="Greeting ascending"
COM_HELLOWORLD_GREETING_DESC="Greeting descending"
COM_HELLOWORLD_AUTHOR_ASC="Author ascending"
COM_HELLOWORLD_AUTHOR_DESC="Author descending"
COM_HELLOWORLD_CREATED_ASC="Creation date ascending"
COM_HELLOWORLD_CREATED_DESC="Creation date descending"
COM_HELLOWORLD_PUBLISHED_ASC="Unpublished first"
COM_HELLOWORLD_PUBLISHED_DESC="Published first"
COM_HELLOWORLD_LANGUAGE_ASC="Language ascending"
COM_HELLOWORLD_LANGUAGE_DESC="Language descending"
COM_HELLOWORLD_ASSOCIATION_ASC="Association ascending"
COM_HELLOWORLD_ASSOCIATION_DESC="Association descending"
COM_HELLOWORLD_ACCESS_ASC="Access ascending"
COM_HELLOWORLD_ACCESS_DESC="Access descending"
; Helloworld menuitem - selecting a greeting via modal
COM_HELLOWORLD_MENUITEM_SELECT_MODAL_TITLE="Select greeting"
COM_HELLOWORLD_MENUITEM_SELECT_HELLOWORLD="Select"
COM_HELLOWORLD_MENUITEM_SELECT_BUTTON_TOOLTIP="Select a helloworld greeting"
; Checking in records
COM_HELLOWORLD_N_ITEMS_CHECKED_IN_0="No records checked in."
COM_HELLOWORLD_N_ITEMS_CHECKED_IN_1="%d record successfully checked in."
COM_HELLOWORLD_N_ITEMS_CHECKED_IN_MORE="%d records successfully checked in."
; Batch functionality
COM_HELLOWORLD_BATCH_OPTIONS="Helloworld component batch options"
COM_HELLOWORLD_BATCH_SETPOSITION_LABEL="Set location"
COM_HELLOWORLD_BATCH_KEEP_POSITION="Keep existing location"
COM_HELLOWORLD_BATCH_CHANGE_POSITION="Change location"

Packaging the Component[edit]

Contents of your code directory. Each file link below takes you to the step in the tutorial which has the latest version of that source code file.

helloworld.xml

<?xml version="1.0" encoding="utf-8"?>
<extension type="component" version="3.0" method="upgrade">

	<name>COM_HELLOWORLD</name>
	<!-- The following elements are optional and free of formatting constraints -->
	<creationDate>January 2018</creationDate>
	<author>John Doe</author>
	<authorEmail>john.doe@example.org</authorEmail>
	<authorUrl>http://www.example.org</authorUrl>
	<copyright>Copyright Info</copyright>
	<license>License Info</license>
	<!--  The version string is recorded in the components table -->
	<version>0.0.32</version>
	<!-- The description is optional and defaults to the name -->
	<description>COM_HELLOWORLD_DESCRIPTION</description>

	<!-- Runs on install/uninstall/update; New in 2.5 -->
	<scriptfile>script.php</scriptfile>

	<install> <!-- Runs on install -->
		<sql>
			<file driver="mysql" charset="utf8">sql/install.mysql.utf8.sql</file>
		</sql>
	</install>
	<uninstall> <!-- Runs on uninstall -->
		<sql>
			<file driver="mysql" charset="utf8">sql/uninstall.mysql.utf8.sql</file>
		</sql>
	</uninstall>
	<update> <!-- Runs on update; New since J2.5 -->
		<schemas>
			<schemapath type="mysql">sql/updates/mysql</schemapath>
		</schemas>
	</update>

	<!-- Site Main File Copy Section -->
	<!-- Note the folder attribute: This attribute describes the folder
		to copy FROM in the package to install therefore files copied
		in this section are copied from /site/ in the package -->
	<files folder="site">
		<filename>index.html</filename>
		<filename>helloworld.php</filename>
		<filename>controller.php</filename>
		<filename>router.php</filename>
		<folder>controllers</folder>
		<folder>views</folder>
		<folder>models</folder>
		<folder>helpers</folder>
	</files>

		<languages folder="site/language">
			<language tag="en-GB">en-GB/en-GB.com_helloworld.ini</language>
			<language tag="fr-FR">fr-FR/fr-FR.com_helloworld.ini</language>
		</languages>

	<media destination="com_helloworld" folder="media">
		<filename>index.html</filename>
		<folder>images</folder>
		<folder>js</folder>
		<folder>css</folder>
	</media>

	<administration>
		<!-- Administration Menu Section -->
		<menu link='index.php?option=com_helloworld' img="../media/com_helloworld/images/tux-16x16.png">COM_HELLOWORLD_MENU</menu>
		<!-- Administration Main File Copy Section -->
		<!-- Note the folder attribute: This attribute describes the folder
			to copy FROM in the package to install therefore files copied
			in this section are copied from /admin/ in the package -->
		<files folder="admin">
			<!-- Admin Main File Copy Section -->
			<filename>index.html</filename>
			<filename>config.xml</filename>
			<filename>helloworld.php</filename>
			<filename>controller.php</filename>
			<filename>access.xml</filename>
			<!-- SQL files section -->
			<folder>sql</folder>
			<!-- tables files section -->
			<folder>tables</folder>
			<!-- models files section -->
			<folder>models</folder>
			<!-- views files section -->
			<folder>views</folder>
			<!-- controllers files section -->
			<folder>controllers</folder>
			<!-- helpers files section -->
			<folder>helpers</folder>
			<!-- layout files section -->
			<folder>layouts</folder>
		</files>
		<languages folder="admin/language">
			<language tag="en-GB">en-GB/en-GB.com_helloworld.ini</language>
			<language tag="en-GB">en-GB/en-GB.com_helloworld.sys.ini</language>
			<language tag="fr-FR">fr-FR/fr-FR.com_helloworld.ini</language>
			<language tag="fr-FR">fr-FR/fr-FR.com_helloworld.sys.ini</language>
		</languages>
	</administration>

</extension>

Contributors[edit]