1099 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			1099 lines
		
	
	
		
			33 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| /**
 | |
|  * Attachments for extensions
 | |
|  *
 | |
|  * @package		Attachments
 | |
|  * @subpackage	Attachments_Plugin_Framework
 | |
|  *
 | |
|  * @author		Jonathan M. Cameron <jmcameron@jmcameron.net>
 | |
|  * @copyright	Copyright (C) 2009-2018 Jonathan M. Cameron, All Rights Reserved
 | |
|  * @license		http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
 | |
|  * @link		http://joomlacode.org/gf/project/attachments/frs/
 | |
|  */
 | |
| 
 | |
| // No direct access
 | |
| defined('_JEXEC') or die('Restricted access');
 | |
| 
 | |
| /** Load the attachments helper */
 | |
| require_once JPATH_SITE . '/components/com_attachments/helper.php';
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Plugins for Attachments
 | |
|  *
 | |
|  * AttachmentsPlugin is the base class for all the plugins to allow
 | |
|  * attaching files to various types of content entities
 | |
|  *
 | |
|  * The derived attachments plugin class must be in the main PHP file for that
 | |
|  * plugin.	  For instance for content articles or categories, the parent type
 | |
|  * is 'com_content'.  The parent type is simply the name of the component
 | |
|  * involved (eg, 'com_content').  The derived attachments plugin class (such
 | |
|  * as 'AttachmentsPlugin_com_content') should be defined in the main file for
 | |
|  * the plugin (eg, attachments_for_conent.php).
 | |
|  *
 | |
|  * Derived attachments plugin classes must also include the following lines of
 | |
|  * code after the class definition to register the derived class with the
 | |
|  * Attachments plugin manager:
 | |
|  *
 | |
|  *	   $apm = getAttachmentsPluginManager();
 | |
|  *	   $apm->addParentType('com_content');
 | |
|  *
 | |
|  * where 'com_content' should be replaced by the name of the appropriate
 | |
|  * parent type (component).
 | |
|  *
 | |
|  * @package	 Attachments
 | |
|  * @since	 3.0
 | |
|  */
 | |
| class AttachmentsPlugin extends JPlugin
 | |
| {
 | |
| 	/** Parent_type: com_content, com_quickfaq, etc
 | |
| 	 */
 | |
| 	protected $parent_type = null;
 | |
| 
 | |
| 	/** Name for the default parent_entity type
 | |
| 	 *
 | |
| 	 * Note that this name will be used for a directory for attachments entries
 | |
| 	 * and should not contain any spaces.  It should correspond to the default
 | |
| 	 * entity.	  For instance, for com_content, it will be 'article';
 | |
| 	 */
 | |
| 	protected $default_entity = null;
 | |
| 
 | |
| 	/** known entities
 | |
| 	 */
 | |
| 	protected $entities = null;
 | |
| 
 | |
| 	/** An associative array of entity names
 | |
| 	 *
 | |
| 	 *	  For each type of attachments plugin, there will be a default
 | |
| 	 *	  entity types.	 For com_content, the default is 'article'.	 If
 | |
| 	 *	  the $default value for the function calls below is omitted,
 | |
| 	 *	  the entity is assumed to be 'article'.	In some cases, the
 | |
| 	 *	  actual proper name of the entity will be available and will be
 | |
| 	 *	  passed in to the $default argument.	  It is important that the
 | |
| 	 *	  plugin code recognizes that the entity 'default' is an alias
 | |
| 	 *	  for 'article'.	This array allows a simple associative array
 | |
| 	 *	  lookup to transform 'default' to 'article'.
 | |
| 	 */
 | |
| 	protected $entity_name = Array();
 | |
| 
 | |
| 	/** An associative array of entity tables
 | |
| 	 */
 | |
| 	protected $entity_table = Array();
 | |
| 
 | |
| 	/** An associative array of entity id fields
 | |
| 	 *	  (in same table as the title)
 | |
| 	 */
 | |
| 	protected $entity_id_field = Array();
 | |
| 
 | |
| 	/** An associative array of entity title fields
 | |
| 	 */
 | |
| 	protected $entity_title_field = Array();
 | |
| 
 | |
| 	/** An associative array of parent creator user ID fields
 | |
| 	 */
 | |
| 	protected $parent_creator_id_field = Array();
 | |
| 
 | |
| 	/** Flag indicating if the language file haas been loaded
 | |
| 	 */
 | |
| 	protected $language_loaded = false;
 | |
| 
 | |
| 	/** Cache for parentExists check
 | |
| 	 */
 | |
| 	protected $parent_exists_cache = Array();
 | |
| 
 | |
| 	/** Cache for parent titles
 | |
| 	 */
 | |
| 	protected $title_cache = Array();
 | |
| 
 | |
| 	/** Cache for parameters for the com_attachments component
 | |
| 	 */
 | |
| 	private $com_attachments_params = null;
 | |
| 
 | |
| 	/**
 | |
| 	 * Constructor
 | |
| 	 *
 | |
| 	 * @param	object	&$subject  The object to observe
 | |
| 	 * @param	array	$config	   An optional associative array of configuration settings.
 | |
| 	 * Recognized key values include 'name', 'group', 'params', 'language'
 | |
| 	 * (this list is not meant to be comprehensive).
 | |
| 	 */
 | |
| 	public function __construct(&$subject, $config = array())
 | |
| 	{
 | |
| 		parent::__construct($subject, $config);
 | |
| 
 | |
| 		// Save the plugin type
 | |
| 		$this->_type = 'attachments';
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Get the attachments parameter object
 | |
| 	 *
 | |
| 	 * @return	 object	 com_attachments parameter object
 | |
| 	 */
 | |
| 	public function attachmentsParams()
 | |
| 	{
 | |
| 		if ($this->com_attachments_params == null)
 | |
| 		{
 | |
| 			jimport('joomla.application.component.helper');
 | |
| 			$this->com_attachments_params = JComponentHelper::getParams('com_attachments');
 | |
| 		}
 | |
| 
 | |
| 		return $this->com_attachments_params;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Return the parent entity / row ID
 | |
| 	 *
 | |
| 	 * This will only be called by the main attachments 'onPrepareContent'
 | |
| 	 * plugin if $attachment ($row) does not have an id
 | |
| 	 *
 | |
| 	 * @param	object	&$attachment  the attachment
 | |
| 	 *
 | |
| 	 * @return id if found, false if this is not a valid parent
 | |
| 	 */
 | |
| 	public function getParentId(&$attachment)
 | |
| 	{
 | |
| 		return JRequest::getInt('id', false);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Return the component name for this parent object
 | |
| 	 *
 | |
| 	 * @return the component name for this parent object
 | |
| 	 */
 | |
| 	public function getParentType()
 | |
| 	{
 | |
| 		return $this->parent_type;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Return a string of the where clause for filtering the the backend list of attachments
 | |
| 	 *
 | |
| 	 * @param	string	$parent_state	the state ('ALL', 'PUBLISHED', 'UNPUBLISHED', 'ARCHIVED', 'NONE')
 | |
| 	 * @param	string	$filter_entity	the entity filter ('ALL', 'ARTICLE', 'CATEGORY', etc)
 | |
| 	 *
 | |
| 	 * @return an array of (join_clause, where_clause) items
 | |
| 	 */
 | |
| 	public function getParentPublishedFilter($parent_state, $filter_entity)
 | |
| 	{
 | |
| 		return array();
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Determine the parent entity
 | |
| 	 *
 | |
| 	 * From the view and the class of the parent (row of onPrepareContent plugin),
 | |
| 	 * determine what the entity type is for this entity.
 | |
| 	 *
 | |
| 	 * Derived classes MUST overrride this
 | |
| 	 *
 | |
| 	 * @param	&object	 &$parent  The object for the parent (row) that onPrepareContent gets
 | |
| 	 *
 | |
| 	 * @return the correct entity (eg, 'default', 'category', etc) or false if this entity should not be displayed.
 | |
| 	 */
 | |
| 	public function determineParentEntity(&$parent)
 | |
| 	{
 | |
| 		return 'default';
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Return the name of the field with the content item text
 | |
| 	 *
 | |
| 	 * During the display of content items (eg, articles, categories), the
 | |
| 	 * onContentPrepare (etc) callbacks are used to insert attachments lists.
 | |
| 	 * The second argument of the onContentPrepare() function is an object
 | |
| 	 * (usually $row) for the content item (eg, article).  This function will
 | |
| 	 * return the appropriate field for the text of the content item.  In some
 | |
| 	 * cases it is 'text', in others, 'introtext'.	Attachments plugins can
 | |
| 	 * override this function to provide the field name more intelligently.
 | |
| 	 *
 | |
| 	 * Note: returns null if the text field is unknown/not present.
 | |
| 	 *
 | |
| 	 * @param	&object	 &$row			 the content object (eg, article) being displayed
 | |
| 	 * @param	string	 $parent_entity	 the type of entity for this content item.
 | |
| 	 *
 | |
| 	 * @return string name of the text field of this content item object.
 | |
| 	 */
 | |
| 	protected function getTextFieldName(&$row, $parent_entity)
 | |
| 	{
 | |
| 		$text_field_name = null;
 | |
| 
 | |
| 		// Ignore items without the normal 'text' field
 | |
| 		if (isset($row->text))
 | |
| 		{
 | |
| 			$text_field_name = 'text';
 | |
| 		}
 | |
| 		elseif (isset($row->fulltext))
 | |
| 		{
 | |
| 			$text_field_name = 'fulltext';
 | |
| 		}
 | |
| 		elseif (isset($row->introtext))
 | |
| 		{
 | |
| 			$text_field_name = 'introtext';
 | |
| 		}
 | |
| 
 | |
| 		return $text_field_name;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Return the array of entity IDs for all content items supported by this parent object
 | |
| 	 *
 | |
| 	 * @return the array of entities supported by this parent object
 | |
| 	 */
 | |
| 	public function getEntities()
 | |
| 	{
 | |
| 		return $this->entities;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Get the default entity ID
 | |
| 	 *
 | |
| 	 * @return string the default entity ID
 | |
| 	 */
 | |
| 	public function getDefaultEntity()
 | |
| 	{
 | |
| 		return $this->default_entity;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Get the canonical extension entity Id (eg, 'article' instead of 'default')
 | |
| 	 *
 | |
| 	 * This is the canonical Id of content element/item to which attachments will be added.
 | |
| 	 *
 | |
| 	 * that each content type ($option) may support several different entities
 | |
| 	 * (for attachments) and some entities may have more than one name.
 | |
| 	 *
 | |
| 	 * Note, for com_content, the default is 'article'
 | |
| 	 *
 | |
| 	 * @param	string	$parent_entity	the type of entity for this parent type
 | |
| 	 *
 | |
| 	 * @return the canonical extension entity
 | |
| 	 */
 | |
| 	public function getCanonicalEntityId($parent_entity)
 | |
| 	{
 | |
| 		// It it is a known entity, just return it
 | |
| 		if (is_array($this->entities) && in_array($parent_entity, $this->entities))
 | |
| 		{
 | |
| 			return $parent_entity;
 | |
| 		}
 | |
| 
 | |
| 		// Check aliases
 | |
| 		if (is_array($this->entities) && array_key_exists($parent_entity, $this->entity_name))
 | |
| 		{
 | |
| 			return $this->entity_name[$parent_entity];
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			$lang = JFactory::getLanguage();
 | |
| 			$lang->load('plg_attachments_attachments_plugin_framework', dirname(__FILE__));
 | |
| 			$errmsg = JText::sprintf('ATTACH_ERROR_INVALID_ENTITY_S_FOR_PARENT_S', $parent_entity, $this->parent_type) . ' (ERR 300)';
 | |
| 			JError::raiseError(500, $errmsg);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Get the path for the uploaded file (on the server file system)
 | |
| 	 *
 | |
| 	 * Note that this does not include the base directory for attachments.
 | |
| 	 *
 | |
| 	 * @param	string	$parent_entity	the type of entity for this parent type
 | |
| 	 * @param	int		$parent_id		the ID for the parent object
 | |
| 	 * @param	int		$attachment_id	the ID for the attachment
 | |
| 	 *
 | |
| 	 * @return string the directory name for this entity (with trailing '/'!)
 | |
| 	 */
 | |
| 	public function getAttachmentPath($parent_entity, $parent_id, $attachment_id)
 | |
| 	{
 | |
| 		$parent_entity = $this->getCanonicalEntityId($parent_entity);
 | |
| 
 | |
| 		$path = sprintf("%s/%d/", $parent_entity, $parent_id);
 | |
| 
 | |
| 		return $path;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Get the name or title for the specified object
 | |
| 	 *
 | |
| 	 * @param	int		$parent_id		the ID for this parent object
 | |
| 	 * @param	string	$parent_entity	the type of entity for this parent type
 | |
| 	 *
 | |
| 	 * @return the name or title for the specified object
 | |
| 	 */
 | |
| 	public function getTitle($parent_id, $parent_entity = 'default')
 | |
| 	{
 | |
| 		// Short-circuit if there is no parent ID
 | |
| 		if (!is_numeric($parent_id))
 | |
| 		{
 | |
| 			return '';
 | |
| 		}
 | |
| 
 | |
| 		$parent_entity = $this->getCanonicalEntityId($parent_entity);
 | |
| 
 | |
| 		// Check the cache first
 | |
| 		$cache_key = $parent_entity . (int) $parent_id;
 | |
| 		if (array_key_exists($cache_key, $this->title_cache))
 | |
| 		{
 | |
| 			return $this->title_cache[$cache_key];
 | |
| 		}
 | |
| 
 | |
| 		$entity_table		= $this->entity_table[$parent_entity];
 | |
| 		$entity_title_field = $this->entity_title_field[$parent_entity];
 | |
| 		$entity_id_field	= $this->entity_id_field[$parent_entity];
 | |
| 
 | |
| 		// Make sure the parent exists
 | |
| 		if (!$this->parentExists($parent_id, $parent_entity))
 | |
| 		{
 | |
| 			/* Do not error out; this is most likely to occur in the backend
 | |
| 			 * when an article with attachments has been deleted without
 | |
| 			 * deleting the attachments.  But we still need list it!
 | |
| 			 */
 | |
| 			return '';
 | |
| 		}
 | |
| 
 | |
| 		// Look up the title
 | |
| 		$db	   = JFactory::getDBO();
 | |
| 		$query = $db->getQuery(true);
 | |
| 		$query->select($entity_title_field)->from("#__$entity_table");
 | |
| 		$query->where("$entity_id_field=" . (int) $parent_id);
 | |
| 		$db->setQuery($query);
 | |
| 		$title = $db->loadResult();
 | |
| 		if ($db->getErrorNum())
 | |
| 		{
 | |
| 			$parent_entity_name = JText::_('ATTACH_' . $parent_entity);
 | |
| 			$errmsg				= JText::sprintf('ATTACH_ERROR_GETTING_PARENT_S_TITLE_FOR_ID_N',
 | |
| 												 $parent_entity_name, $parent_id) . ' (ERR 301)';
 | |
| 			JError::raiseError(500, $errmsg);
 | |
| 		}
 | |
| 
 | |
| 		$this->title_cache[$cache_key] = $title;
 | |
| 
 | |
| 		return $this->title_cache[$cache_key];
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Return an array of entity items (with id,title pairs for each item)
 | |
| 	 *
 | |
| 	 * @param	string	$parent_entity	the type of entity to search for
 | |
| 	 * @param	string	$filter			filter the results for matches for this filter string
 | |
| 	 *
 | |
| 	 * @return the array of entity id,title pairs
 | |
| 	 */
 | |
| 	public function getEntityItems($parent_entity = 'default', $filter = '')
 | |
| 	{
 | |
| 		$parent_entity = $this->getCanonicalEntityId($parent_entity);
 | |
| 
 | |
| 		$entity_table		= $this->entity_table[$parent_entity];
 | |
| 		$entity_title_field = $this->entity_title_field[$parent_entity];
 | |
| 		$entity_id_field	= $this->entity_id_field[$parent_entity];
 | |
| 
 | |
| 		// Get the ordering information
 | |
| 		$app	   = JFactory::getApplication();
 | |
| 		$order	   = $app->getUserStateFromRequest('com_attachments.selectEntity.filter_order',
 | |
| 												   'filter_order', '', 'cmd');
 | |
| 		$order_Dir = $app->getUserStateFromRequest('com_attachments.selectEntity.filter_order_Dir',
 | |
| 												   'filter_order_Dir', '', 'word');
 | |
| 
 | |
| 		// Get all the items
 | |
| 		$db	   = JFactory::getDBO();
 | |
| 		$query = $db->getQuery(true);
 | |
| 		$query->select("DISTINCT $entity_id_field,$entity_title_field");
 | |
| 		$query->from("#__$entity_table");
 | |
| 		if ($filter)
 | |
| 		{
 | |
| 			$filter = $db->quote('%' . $db->escape($filter, true) . '%', false);
 | |
| 			$query->where($entity_title_field . ' LIKE ' . $filter);
 | |
| 		}
 | |
| 
 | |
| 		if ($order)
 | |
| 		{
 | |
| 			if ($order == 'title')
 | |
| 			{
 | |
| 				$query->order("$entity_title_field " . $order_Dir);
 | |
| 			}
 | |
| 			elseif ($order == 'id')
 | |
| 			{
 | |
| 				$query->order("$entity_id_field " . $order_Dir);
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				// Ignore unrecognized columns
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// Do the query
 | |
| 		$db->setQuery($query);
 | |
| 		if ($db->getErrorNum())
 | |
| 		{
 | |
| 			$parent_entity_name = JText::_('ATTACH_' . $parent_entity);
 | |
| 			$errmsg				= JText::sprintf('ATTACH_ERROR_GETTING_LIST_OF_ENTITY_S_ITEMS', $parent_entity_name) . ' (ERR 302)';
 | |
| 			JError::raiseError(500, $errmsg);
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			$items = $db->loadObjectList();
 | |
| 		}
 | |
| 
 | |
| 		if ($items == null)
 | |
| 		{
 | |
| 			return null;
 | |
| 		}
 | |
| 
 | |
| 		// Make sure the the ids are called 'id' in the list
 | |
| 		if ($entity_id_field != 'id')
 | |
| 		{
 | |
| 			foreach ($items as $item)
 | |
| 			{
 | |
| 				$item->id = $item->$entity_id_field;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// Make sure the the titles are called 'title' in the list
 | |
| 		if ($entity_title_field != 'title')
 | |
| 		{
 | |
| 			foreach ($items as $item)
 | |
| 			{
 | |
| 				$item->title = $item->$entity_title_field;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return $items;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Return the URL that can be called to select a specific content item.
 | |
| 	 *
 | |
| 	 * @param	string	$parent_entity	the type of entity to select from
 | |
| 	 *
 | |
| 	 * @return the URL that can be called to select a specific content item
 | |
| 	 */
 | |
| 	public function getSelectEntityURL($parent_entity = 'default')
 | |
| 	{
 | |
| 		// Add on the parent type and entity
 | |
| 		$entity = "&parent_type=" . $this->parent_type;
 | |
| 
 | |
| 		if ($parent_entity != 'default')
 | |
| 		{
 | |
| 			$entity .= '.' . $parent_entity;
 | |
| 		}
 | |
| 
 | |
| 		return "index.php?option=com_attachments&task=selectEntity" . $entity . "&tmpl=component";
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Return the ID of the creator/owner of the parent entity
 | |
| 	 *
 | |
| 	 * @param	int		$parent_id		the ID for the parent object
 | |
| 	 * @param	string	$parent_entity	the type of entity for this parent type
 | |
| 	 *
 | |
| 	 * @return creators id if found, 0 otherwise
 | |
| 	 */
 | |
| 	public function getParentCreatorId($parent_id, $parent_entity = 'default')
 | |
| 	{
 | |
| 		JError::raiseError(501, JText::_('ATTACH_NOT_IMPLEMENTED'));
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Get a URL to view the entity
 | |
| 	 *
 | |
| 	 * @param	int		$parent_id		the ID for this parent object
 | |
| 	 * @param	string	$parent_entity	the type of entity for this parent type
 | |
| 	 *
 | |
| 	 * @return a URL to view the entity (non-SEF form)
 | |
| 	 */
 | |
| 	public function getEntityViewURL($parent_id, $parent_entity = 'default')
 | |
| 	{
 | |
| 		return null;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Get a URL to add an attachment to a specific entity
 | |
| 	 *
 | |
| 	 * @param	int		$parent_id		the ID for the parent entity object (null if the parent does not exist)
 | |
| 	 * @param	string	$parent_entity	the type of entity for this parent type
 | |
| 	 * @param	string	$from			where the call should return to
 | |
| 	 *
 | |
| 	 * @return the url to add a new attachments to the specified entity
 | |
| 	 */
 | |
| 	public function getEntityAddUrl($parent_id, $parent_entity = 'default', $from = 'closeme')
 | |
| 	{
 | |
| 		$app = JFactory::getApplication();
 | |
| 
 | |
| 		if ($app->isAdmin())
 | |
| 		{
 | |
| 			$task = 'add';
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			$task = 'upload';
 | |
| 		}
 | |
| 
 | |
| 		$url = "index.php?option=com_attachments&task=$task";
 | |
| 		if ($parent_id == null)
 | |
| 		{
 | |
| 			$url .= "&parent_id=$parent_id,new";
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			$url .= "&parent_id=$parent_id";
 | |
| 		}
 | |
| 
 | |
| 		$url .= "&parent_type=" . $this->parent_type . "&from=$from";
 | |
| 
 | |
| 		return $url;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Check to see if a custom title applies to this parent
 | |
| 	 *
 | |
| 	 * Note: this public function assumes that the parent_id's match
 | |
| 	 *
 | |
| 	 * @param	string	$parent_entity		   the parent entity for the parent of the list
 | |
| 	 * @param	string	$rtitle_parent_entity  the entity of the candidate attachment list title (from params)
 | |
| 	 *
 | |
| 	 * @return true if the custom title should be used
 | |
| 	 */
 | |
| 	public function checkAttachmentsListTitle($parent_entity, $rtitle_parent_entity)
 | |
| 	{
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Get the title for the attachments list for this parent
 | |
| 	 *
 | |
| 	 * @param	string	$title			the untranslated title token (either 'ATTACH_ATTACHMENTS_TITLE' or 'ATTACH_EXISTING_ATTACHMENTS')
 | |
| 	 * @param	int		$parent_id		the ID for the parent entity object (null if the parent does not exist)
 | |
| 	 * @param	string	$parent_entity	the type of entity for this parent type
 | |
| 	 *
 | |
| 	 * @return the translated title string
 | |
| 	 */
 | |
| 	public function attachmentsListTitle($title, $parent_id, $parent_entity = 'default')
 | |
| 	{
 | |
| 		$aparams	 = $this->attachmentsParams();
 | |
| 		$rtitle_str = $aparams->get('attachments_titles', '');
 | |
| 		if (($title != 'ATTACH_EXISTING_ATTACHMENTS') && ($rtitle_str != ''))
 | |
| 		{
 | |
| 			$rtitle_list = preg_split("[\n|\r]", $rtitle_str);
 | |
| 
 | |
| 			foreach ($rtitle_list as $rtitle)
 | |
| 			{
 | |
| 				if (preg_match('|^([0-9]+)\s*([^$]+)$|', $rtitle, $match))
 | |
| 				{
 | |
| 					// Process:		3 new title
 | |
| 					// NOTE: This form only applies to articles and will be ignored for anything else
 | |
| 					if ((int) $parent_id != (int) $match[1])
 | |
| 					{
 | |
| 						continue;
 | |
| 					}
 | |
| 
 | |
| 					if (($this->parent_type == 'com_content') && (($parent_entity == 'default') || ($parent_entity == 'article')))
 | |
| 					{
 | |
| 						$title = $match[2];
 | |
| 					}
 | |
| 				}
 | |
| 				elseif (preg_match('|^([a-zA-Z0-9_/-]+):([0-9]+)\s*([^$]+)$|', $rtitle, $match))
 | |
| 				{
 | |
| 					// Process:		 entity:3 new title
 | |
| 					if ((int) $parent_id != (int) $match[2])
 | |
| 					{
 | |
| 						continue;
 | |
| 					}
 | |
| 
 | |
| 					if ($this->checkAttachmentsListTitle($parent_entity, $match[1]))
 | |
| 					{
 | |
| 						$title = $match[3];
 | |
| 					}
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					// With no entity/numeric prefix, the title applies to all attachments lists
 | |
| 					$rtitle = trim($rtitle);
 | |
| 					if ($rtitle != '')
 | |
| 					{
 | |
| 						$title = $rtitle;
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return JText::_($title);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Does the parent exist?
 | |
| 	 *
 | |
| 	 * @param	int		$parent_id		the ID for this parent object
 | |
| 	 * @param	string	$parent_entity	the type of entity for this parent type
 | |
| 	 *
 | |
| 	 * @return true if the parent exists
 | |
| 	 */
 | |
| 	public function parentExists($parent_id, $parent_entity = 'default')
 | |
| 	{
 | |
| 		$parent_entity = $this->getCanonicalEntityId($parent_entity);
 | |
| 
 | |
| 		// Check the cache first
 | |
| 		$cache_key = $parent_entity . (int) $parent_id;
 | |
| 		if (array_key_exists($cache_key, $this->parent_exists_cache))
 | |
| 		{
 | |
| 			return $this->parent_exists_cache[$cache_key];
 | |
| 		}
 | |
| 
 | |
| 		// First time, so look up the parent
 | |
| 		$entity_table	 = $this->entity_table[$parent_entity];
 | |
| 		$entity_id_field = $this->entity_id_field[$parent_entity];
 | |
| 		$db				 = JFactory::getDBO();
 | |
| 		$query			 = $db->getQuery(true);
 | |
| 		$query->select($entity_id_field)->from("#__$entity_table");
 | |
| 		$query->where("$entity_id_field=" . (int) $parent_id);
 | |
| 		$db->setQuery($query, 0, 1);
 | |
| 		$result = $db->loadResult();
 | |
| 		if ($result === null)
 | |
| 		{
 | |
| 			$this->parent_exists_cache[$cache_key] = false;
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			$this->parent_exists_cache[$cache_key] = (int) $parent_id == (int) $result;
 | |
| 		}
 | |
| 
 | |
| 		return $this->parent_exists_cache[$cache_key];
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Is the parent new (based on the parent_id)
 | |
| 	 *
 | |
| 	 * @param	object	&$attachment  the attachment
 | |
| 	 *
 | |
| 	 * @return true if the parent is new (being created)
 | |
| 	 */
 | |
| 	public function newParent(&$attachment)
 | |
| 	{
 | |
| 		// Assume parent_id == 0 means the parent is new
 | |
| 		// (NOTE: This may not be true for some components)
 | |
| 		return $attachment->parent_id == 0;
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 	/**
 | |
| 	 * Check to see if the parent is published
 | |
| 	 *
 | |
| 	 * @param	int		$parent_id		the ID for this parent object
 | |
| 	 * @param	string	$parent_entity	the type of entity for this parent type
 | |
| 	 *
 | |
| 	 * @return true if the parent is published
 | |
| 	 */
 | |
| 	public function isParentPublished($parent_id, $parent_entity = 'default')
 | |
| 	{
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Check to see if the parent is archived
 | |
| 	 *
 | |
| 	 * @param	int		$parent_id		the ID for this parent object
 | |
| 	 * @param	string	$parent_entity	the type of entity for this parent type
 | |
| 	 *
 | |
| 	 * @return true if the parent is archived
 | |
| 	 */
 | |
| 	public function isParentArchived($parent_id, $parent_entity = 'default')
 | |
| 	{
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * May the parent be viewed by the user?
 | |
| 	 *
 | |
| 	 * This public function should be called by derived class functions.
 | |
| 	 *
 | |
| 	 * Note that this base class function only determines necessary
 | |
| 	 * conditions. If this function returns FALSE, then viewing is definitely
 | |
| 	 * not permitted. If this function returns TRUE, then the derived classes
 | |
| 	 * also need to check whether viewing the specific content item (eg,
 | |
| 	 * article) is permitted.
 | |
| 	 *
 | |
| 	 * @param	int		$parent_id		the ID for this parent object
 | |
| 	 * @param	string	$parent_entity	the type of entity for this parent type
 | |
| 	 * @param	object	$user_id		the user_id to check (optional, primarily for testing)
 | |
| 	 *
 | |
| 	 * @return true if the parent may be viewed by the user
 | |
| 	 */
 | |
| 	public function userMayViewParent($parent_id, $parent_entity = 'default', $user_id = null)
 | |
| 	{
 | |
| 		JError::raiseError(501, JText::_('ATTACH_NOT_IMPLEMENTED'));
 | |
| 	}
 | |
| 
 | |
| 	/** Return true if the attachments should be hidden for this parent
 | |
| 	 *
 | |
| 	 * @param	&object	 &$parent		 the object for the parent that onPrepareContent gives
 | |
| 	 * @param	int		 $parent_id		 the ID of the parent the attachment is attached to
 | |
| 	 * @param	string	 $parent_entity	 the type of entity for this parent type
 | |
| 	 *
 | |
| 	 * Note: this generic version only implements the 'frontpage' option.  All
 | |
| 	 *		   other options should be handled by the derived classes for other
 | |
| 	 *		   content types.
 | |
| 	 *
 | |
| 	 * @return true if the attachments should be hidden for this parent
 | |
| 	 */
 | |
| 	public function attachmentsHiddenForParent(&$parent, $parent_id, $parent_entity)
 | |
| 	{
 | |
| 		$layout = JRequest::getCmd('layout');
 | |
| 		$aparams = $this->attachmentsParams();
 | |
| 
 | |
| 		// Check to see whether the attachments should be hidden on the front page
 | |
| 		$hide_on_frontpage = $aparams->get('hide_on_frontpage', false);
 | |
| 		if ($hide_on_frontpage && (JRequest::getVar('view') == 'featured'))
 | |
| 		{
 | |
| 			return true;
 | |
| 		}
 | |
| 
 | |
| 		// Hide on blog pages?
 | |
| 		$hide_on_blogs = $aparams->get('hide_on_blogs', false);
 | |
| 		if ($hide_on_blogs && ($layout == 'blog'))
 | |
| 		{
 | |
| 			return true;
 | |
| 		}
 | |
| 
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Return true if the user may add an attachment to this parent
 | |
| 	 *
 | |
| 	 * (Note that all of the arguments are assumed to be valid; no sanity checking is done.
 | |
| 	 *	  It is up to the caller to validate these objects before calling this function.)
 | |
| 	 *
 | |
| 	 * @param	int		$parent_id		the ID of the parent the attachment is attached to
 | |
| 	 * @param	string	$parent_entity	the type of entity for this parent type
 | |
| 	 * @param	bool	$new_parent		if true, the parent is being created and does not exist yet
 | |
| 	 * @param	object	$user_id		the user_id to check (optional, primarily for testing)
 | |
| 	 *
 | |
| 	 * @return true if this user add attachments to this parent
 | |
| 	 */
 | |
| 	public function userMayAddAttachment($parent_id, $parent_entity, $new_parent = false, $user_id = null)
 | |
| 	{
 | |
| 		JError::raiseError(501, JText::_('ATTACH_NOT_IMPLEMENTED'));
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Return true if this user may edit (modify/delete/update) this attachment for this parent
 | |
| 	 *
 | |
| 	 * (Note that all of the arguments are assumed to be valid; no sanity checking is done.
 | |
| 	 *	  It is up to the caller to validate the arguments before calling this function.)
 | |
| 	 *
 | |
| 	 * @param	&record	 &$attachment  database record for the attachment
 | |
| 	 * @param	object	 $user_id	   the user_id to check (optional, primarily for testing)
 | |
| 	 *
 | |
| 	 * @return true if this user may edit this attachment
 | |
| 	 */
 | |
| 	public function userMayEditAttachment(&$attachment, $user_id = null)
 | |
| 	{
 | |
| 		JError::raiseError(501, JText::_('ATTACH_NOT_IMPLEMENTED'));
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Return true if this user may delete this attachment for this parent
 | |
| 	 *
 | |
| 	 * (Note that all of the arguments are assumed to be valid; no sanity checking is done.
 | |
| 	 *	  It is up to the caller to validate the arguments before calling this function.)
 | |
| 	 *
 | |
| 	 * @param	&record	 &$attachment  database record for the attachment
 | |
| 	 * @param	object	 $user_id	   the user_id to check (optional, primarily for testing)
 | |
| 	 *
 | |
| 	 * @return true if this user may delete this attachment
 | |
| 	 */
 | |
| 	public function userMayDeleteAttachment(&$attachment, $user_id = null)
 | |
| 	{
 | |
| 		JError::raiseError(501, JText::_('ATTACH_NOT_IMPLEMENTED'));
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Return true if this user may change the state of this attachment
 | |
| 	 *
 | |
| 	 * (Note that all of the arguments are assumed to be valid; no sanity checking is done.
 | |
| 	 *	  It is up to the caller to validate the arguments before calling this function.)
 | |
| 	 *
 | |
| 	 * @param	int		$parent_id				the ID for the parent object
 | |
| 	 * @param	string	$parent_entity			the type of entity for this parent type
 | |
| 	 * @param	int		$attachment_creator_id	the ID of the creator of the attachment
 | |
| 	 * @param	object	$user_id				the user_id to check (optional, primarily for testing)
 | |
| 	 *
 | |
| 	 * @return true if this user may change the state of this attachment
 | |
| 	 */
 | |
| 	public function userMayChangeAttachmentState($parent_id, $parent_entity, $attachment_creator_id, $user_id = null)
 | |
| 	{
 | |
| 		JError::raiseError(501, JText::_('ATTACH_NOT_IMPLEMENTED'));
 | |
| 	}
 | |
| 
 | |
| 	/** Check to see if the user may access (see/download) the attachments
 | |
| 	 *
 | |
| 	 * @param	&record	 &$attachment  database record for the attachment
 | |
| 	 * @param	object	 $user_id	   the user_id to check (optional, primarily for testing)
 | |
| 	 *
 | |
| 	 * @return true if access is okay (false if not)
 | |
| 	 */
 | |
| 	public function userMayAccessAttachment(&$attachment, $user_id = null)
 | |
| 	{
 | |
| 		JError::raiseError(501, JText::_('ATTACH_NOT_IMPLEMENTED'));
 | |
| 	}
 | |
| 
 | |
| 	/** Insert the attachments list into the content text (for front end)
 | |
| 	 *
 | |
| 	 * @param	object	&$content		the text of the content item (eg, article text)
 | |
| 	 * @param	int		$parent_id		the ID for the parent object
 | |
| 	 * @param	string	$parent_entity	the type of entity for this parent type
 | |
| 	 *
 | |
| 	 * @return	string	the modified content text (false for failure)
 | |
| 	 */
 | |
| 	public function insertAttachmentsList(&$content, $parent_id, $parent_entity)
 | |
| 	{
 | |
| 		$aparams = $this->attachmentsParams();
 | |
| 
 | |
| 		// Get the desired placement
 | |
| 		$attachments_placement = $aparams->get('attachments_placement', 'end');
 | |
| 		if ($attachments_placement == 'disabled_nofilter')
 | |
| 		{
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		// Determine where we are
 | |
| 		$from	= JRequest::getCmd('view', 'closeme');
 | |
| 		$Itemid = JRequest::getInt('Itemid', 1);
 | |
| 
 | |
| 		// See whether we can display the links to add attachments
 | |
| 		$user_can_add = $this->userMayAddAttachment($parent_id, $parent_entity);
 | |
| 
 | |
| 		// Get the field name for the content item's text
 | |
| 		$text_field_name = $this->getTextFieldName($content, $parent_entity);
 | |
| 		if ($text_field_name === null)
 | |
| 		{
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		// Get the attachments tag, if present
 | |
| 		$attachments_tag	  = '';
 | |
| 		$attachments_tag_args = '';
 | |
| 		$match				  = false;
 | |
| 		if (JString::strpos($content->$text_field_name, '{attachments'))
 | |
| 		{
 | |
| 			if (preg_match('@(<span class="hide_attachments_token">)?{attachments([ ]*:*[^}]+)?}(</span>)?@', $content->$text_field_name, $match))
 | |
| 			{
 | |
| 				$attachments_tag = true;
 | |
| 			}
 | |
| 
 | |
| 			if (isset($match[1]) && $match[1])
 | |
| 			{
 | |
| 				$attachments_tag_args_raw = $match[1];
 | |
| 				$attachments_tag_args	  = ltrim($attachments_tag_args_raw, ' :');
 | |
| 			}
 | |
| 
 | |
| 			if ($attachments_tag)
 | |
| 			{
 | |
| 				$attachments_tag = $match[0];
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// Check the security status
 | |
| 		$attach_dir	  = JPATH_SITE . '/' . AttachmentsDefines::$ATTACHMENTS_SUBDIR;
 | |
| 		$secure		  = $aparams->get('secure', false);
 | |
| 		$hta_filename = $attach_dir . '/ . htaccess';
 | |
| 		if (($secure && !file_exists($hta_filename)) || (!$secure && file_exists($hta_filename)))
 | |
| 		{
 | |
| 			AttachmentsHelper::setup_upload_directory($attach_dir, $secure);
 | |
| 		}
 | |
| 
 | |
| 		// Construct the attachment list (if appropriate)
 | |
| 		$html				 = '';
 | |
| 		$attachments_list	 = false;
 | |
| 		$add_attachement_btn = false;
 | |
| 
 | |
| 		// Get the html for the attachments list
 | |
| 		require_once JPATH_SITE . '/components/com_attachments/controllers/attachments.php';
 | |
| 		$controller		  = new AttachmentsControllerAttachments;
 | |
| 		$attachments_list = $controller->displayString($parent_id, $this->parent_type, $parent_entity, null, true, true, false, $from);
 | |
| 
 | |
| 		// If the attachments list is empty, insert an empty div for it
 | |
| 		if ($attachments_list == '')
 | |
| 		{
 | |
| 			$class_name		  = $aparams->get('attachments_table_style', 'attachmentsList');
 | |
| 			$div_id			  = 'attachmentsList' . '_' . $this->parent_type . '_' . $parent_entity . '_' . (string) $parent_id;
 | |
| 			$attachments_list = "\n<div class=\"$class_name\" id=\"$div_id\"></div>\n";
 | |
| 		}
 | |
| 
 | |
| 		$html .= $attachments_list;
 | |
| 
 | |
| 		if ($html || $user_can_add)
 | |
| 		{
 | |
| 			// Add the style sheet
 | |
| 			JHtml::stylesheet('com_attachments/attachments_list.css', Array(), true);
 | |
| 
 | |
| 			// Handle RTL styling (if necessary)
 | |
| 			$lang = JFactory::getLanguage();
 | |
| 			if ($lang->isRTL())
 | |
| 			{
 | |
| 				JHtml::stylesheet('com_attachments/attachments_list_rtl.css', Array(), true);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// Construct the add-attachments button, if appropriate
 | |
| 		$hide_add_attachments_link = $aparams->get('hide_add_attachments_link', 0);
 | |
| 		if ($user_can_add && !$hide_add_attachments_link)
 | |
| 		{
 | |
| 			$add_attachments_btn = AttachmentsHelper::attachmentButtonsHTML($this->parent_type, $parent_id, $parent_entity, $Itemid, $from);
 | |
| 			$html .= $add_attachments_btn;
 | |
| 		}
 | |
| 
 | |
| 		// Wrap both list and the Add Attachments button in another div
 | |
| 		if ($html)
 | |
| 		{
 | |
| 			$html = "<div class=\"attachmentsContainer\">\n" . $html . "\n</div>";
 | |
| 		}
 | |
| 
 | |
| 		// Finally, add the attachments
 | |
| 
 | |
| 		// NOTE: Hope str_replace() below is UTF8 safe (since the token being replaced is UTF8)...
 | |
| 
 | |
| 		switch ($attachments_placement)
 | |
| 		{
 | |
| 			case 'beginning':
 | |
| 				// Put the attachments list at the beginning
 | |
| 				if ($attachments_list || $user_can_add)
 | |
| 				{
 | |
| 					if ($attachments_tag)
 | |
| 					{
 | |
| 						$content->$text_field_name = $html . $content->$text_field_name;
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						$content->$text_field_name = $html . str_replace($attachments_tag, '', $content->$text_field_name);
 | |
| 					}
 | |
| 				}
 | |
| 				break;
 | |
| 
 | |
| 			case 'custom':
 | |
| 				// Insert the attachments at the desired location
 | |
| 				if ($attachments_list || $user_can_add)
 | |
| 				{
 | |
| 					if ($attachments_tag)
 | |
| 					{
 | |
| 						$content->$text_field_name = str_replace($attachments_tag, $html, $content->$text_field_name);
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						// If there is no tag, insert the attachments at the end
 | |
| 						$content->$text_field_name .= $html;
 | |
| 					}
 | |
| 				}
 | |
| 				break;
 | |
| 
 | |
| 			case 'disabled_filter':
 | |
| 				// Disable and strip out any attachments tags
 | |
| 				if ($attachments_tag)
 | |
| 				{
 | |
| 					$content->$text_field_name = str_replace($attachments_tag, '', $content->$text_field_name);
 | |
| 				}
 | |
| 				break;
 | |
| 
 | |
| 			default:
 | |
| 				// Add the attachments to the end
 | |
| 				if ($attachments_list || $user_can_add)
 | |
| 				{
 | |
| 					if ($attachments_tag)
 | |
| 					{
 | |
| 						$content->$text_field_name = str_replace($attachments_tag, '', $content->$text_field_name) . $html;
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						$content->$text_field_name .= $html;
 | |
| 					}
 | |
| 				}
 | |
| 				break;
 | |
| 		}
 | |
| 
 | |
| 		return $content;
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 	/** Get the parent_id in the component content item editor
 | |
| 	 *	(the article or category editor)
 | |
| 	 *
 | |
| 	 * @param  string  $parent_entity  the type of entity for this parent type
 | |
| 	 *
 | |
| 	 * @return the parent ID, null if the content item is being created, and false if there is no match
 | |
| 	 *
 | |
| 	 * @since	 Attachments 3.2
 | |
| 	 */
 | |
| 	public function getParentIdInEditor($parent_entity, $view, $layout)
 | |
| 	{
 | |
| 		// This should work in the backend for most well-implemented content types--
 | |
| 		// but not for all frontends, especially not com_content/articles
 | |
| 		$id = null;
 | |
| 		if ($view == $parent_entity) {
 | |
| 			$id = JRequest::getInt('id', $default=null);
 | |
| 			}
 | |
| 		else {
 | |
| 			$id = false;
 | |
| 			}
 | |
| 
 | |
| 		// If we got one, convert it to an int
 | |
| 		if (is_numeric($id)) {
 | |
| 			$id = (int)$id;
 | |
| 			}
 | |
| 
 | |
| 		return $id;
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 	/** See if the attachments list should be displayed in its content description editor
 | |
| 	 *
 | |
| 	 * @param	string	$parent_entity	the type of entity for this parent type
 | |
| 	 * @param	string	$view			the view
 | |
| 	 * @param	string	$layout			the layout on the view
 | |
| 	 *
 | |
| 	 * @return	true if the attachments list should be added to the editor
 | |
| 	 */
 | |
| 	public function showAttachmentsInEditor($parent_entity, $view, $layout)
 | |
| 	{
 | |
| 		JError::raiseError(501, JText::_('ATTACH_NOT_IMPLEMENTED'));
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 	/** Insert the attachments list into the entity editor page
 | |
| 	 *
 | |
| 	 * @param	int		$parent_id		the ID for the parent object
 | |
| 	 * @param	string	$parent_entity	the type of entity for this parent type
 | |
| 	 * @param	string	$attachments	the attachments list as a string
 | |
| 	 * @param	string	$body			the editor page text
 | |
| 	 *
 | |
| 	 * @return	string	the modified editor page text (false for failure)
 | |
| 	 */
 | |
| 	public function insertAttachmentsListInEditor($parent_id, $parent_entity, $attachments, $body)
 | |
| 	{
 | |
| 		// Figure out where to insert the attachments list
 | |
| 		$reptag = '<div id="editor-xtd-buttons"';
 | |
| 		if (version_compare(JVERSION, '3.5', 'ge')) {
 | |
| 			if (JFactory::getEditor()->get('_name') == 'tinymce') {
 | |
| 				# Hack because TinyMCE changed the structure
 | |
| 				$reptag = '<div class="toggle-editor btn-toolbar pull-right clearfix"';
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 		// Insert the attachments above the editor buttons
 | |
| 		// NOTE: Assume that anyone editing the entity can see its attachments
 | |
| 		$body = str_replace($reptag, $attachments . $reptag, $body);
 | |
| 		return $body;
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 	/** Known from keywords
 | |
| 	 *
 | |
| 	 * Attachment pop-dialogs will be closed using javascript if they are called from pages of these 'from' types
 | |
| 	 *
 | |
| 	 * @retrun array  An array of known tokens (strings)
 | |
| 	 */
 | |
| 	public function knownFroms()
 | |
| 	{
 | |
| 		// Most components should recognize these
 | |
| 		return Array('editor', 'closeme');
 | |
| 	}
 | |
| 
 | |
| }
 |