Skip to content
Extraits de code Groupes Projets
Controller.php 15,3 ko
Newer Older
  • Learn to ignore specific revisions
  • <?php
    /**
     * Piwik - Open source web analytics
     * 
     * @link http://piwik.org
    
    robocoder's avatar
    robocoder a validé
     * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
    
    robocoder's avatar
    robocoder a validé
     * @category Piwik
    
     * @package Piwik
     */
    
    /**
     * Parent class of all plugins Controllers (located in /plugins/PluginName/Controller.php
     * It defines some helper functions controllers can use.
     * 
     * @package Piwik
     */
    abstract class Piwik_Controller
    {
    	/**
    	 * Plugin name, eg. Referers
    	 * @var string
    	 */
    	protected $pluginName;
    	
    	/**
    	 * Date string
    	 * 
    	 * @var string
    	 */
    	protected $strDate;
    	
    	/**
    	 * Piwik_Date object or null if the requested date is a range
    	 * 
    	 * @var Piwik_Date|null 
    	 */
    	protected $date;
    
    mattpiwik's avatar
    mattpiwik a validé
    	protected $idSite;
    
    mattpiwik's avatar
    mattpiwik a validé
    	protected $site = null;
    
    	
    	/**
    	 * Builds the controller object, reads the date from the request, extracts plugin name from 
    	 */
    	function __construct()
    
    mattpiwik's avatar
    mattpiwik a validé
    	{
    		$this->init();
    	}
    	
    	protected function init()
    
    	{
    		$aPluginName = explode('_', get_class($this));
    		$this->pluginName = $aPluginName[1];
    
    mattpiwik's avatar
    mattpiwik a validé
    		$date = Piwik_Common::getRequestVar('date', 'yesterday', 'string');
    		try {
    			$this->idSite = Piwik_Common::getRequestVar('idSite', false, 'int');
    			$this->site = new Piwik_Site($this->idSite);
    			$date = $this->getDateParameterInTimezone($date, $this->site->getTimezone());
    			$this->setDate($date);
    
    		} catch(Exception $e){
    			// the date looks like YYYY-MM-DD,YYYY-MM-DD or other format
    			$this->date = null;
    		}
    	}
    
    mattpiwik's avatar
    mattpiwik a validé
    	/**
    	 * Helper method to convert "today" or "yesterday" to the default timezone specified.
    	 * If the date is absolute, ie. YYYY-MM-DD, it will not be converted to the timezone
    	 * @param $date today, yesterday, YYYY-MM-DD
    	 * @param $defaultTimezone
    	 * @return Piwik_Date
    	 */
    	protected function getDateParameterInTimezone($date, $defaultTimezone )
    	{
    		$timezone = null;
    		// if the requested date is not YYYY-MM-DD, we need to ensure
    		//  it is relative to the website's timezone
    		if(in_array($date, array('today', 'yesterday')))
    		{
    			// today is at midnight; we really want to get the time now, so that
    			// * if the website is UTC+12 and it is 5PM now in UTC, the calendar will allow to select the UTC "tomorrow"
    			// * if the website is UTC-12 and it is 5AM now in UTC, the calendar will allow to select the UTC "yesterday" 
    			if($date == 'today')
    			{
    				$date = 'now';
    			}
    			elseif($date == 'yesterday')
    			{
    				$date = 'yesterdaySameTime';
    			}
    			$timezone = $defaultTimezone;
    		}
    		return Piwik_Date::factory($date, $timezone);
    	}
    
    	/**
    	 * Sets the date to be used by all other methods in the controller.
    	 * If the date has to be modified, it should be called just after the controller construct
    	 * @param $date
    	 * @return void
    	 */
    	protected function setDate(Piwik_Date $date)
    	{
    		$this->date = $date;
    		$this->strDate = $this->date->toString();
    	}
    	
    
    	/**
    	 * Returns the name of the default method that will be called 
    	 * when visiting: index.php?module=PluginName without the action parameter
    	 * 
    	 * @return string
    	 */
    	function getDefaultAction()
    	{
    		return 'index';
    	}
    
    	/**
    	 * Given an Object implementing Piwik_iView interface, we either:
    	 * - echo the output of the rendering if fetch = false
    	 * - returns the output of the rendering if fetch = true
    	 *
    	 * @param Piwik_ViewDataTable $view
    	 * @param bool $fetch
    	 * @return string|void
    	 */
    
    	protected function renderView( Piwik_ViewDataTable $view, $fetch = false)
    
    		Piwik_PostEvent(	'Controller.renderView', 
    							$this, 
    							array(	'view' => $view,
    									'controllerName' => $view->getCurrentControllerName(),
    									'controllerAction' => $view->getCurrentControllerAction(),
    									'apiMethodToRequestDataTable' => $view->getApiMethodToRequestDataTable(),
    									'controllerActionCalledWhenRequestSubTable' => $view->getControllerActionCalledWhenRequestSubTable(),
    							)
    				);
    
    		$view->main();
    		$rendered = $view->getView()->render();
    		if($fetch)
    		{
    			return $rendered;
    		}
    		echo $rendered;
    	}
    	
    	/**
    	 * Returns a ViewDataTable object of an Evolution graph 
    	 * for the last30 days/weeks/etc. of the current period, relative to the current date.
    	 *
    	 * @param string $currentModuleName
    	 * @param string $currentControllerAction
    	 * @param string $apiMethod
    	 * @return Piwik_ViewDataTable_GenerateGraphHTML_ChartEvolution
    	 */
    	protected function getLastUnitGraph($currentModuleName, $currentControllerAction, $apiMethod)
    	{
    		$view = Piwik_ViewDataTable::factory('graphEvolution');
    		$view->init( $currentModuleName, $currentControllerAction, $apiMethod );
    		
    		// if the date is not yet a nicely formatted date range ie. YYYY-MM-DD,YYYY-MM-DD we build it
    		// otherwise the current controller action is being called with the good date format already so it's fine
    		// see constructor
    		if( !is_null($this->date))
    		{
    			$view->setParametersToModify( 
    
    				$this->getGraphParamsModified( array('date' => $this->strDate))
    
    robocoder's avatar
    robocoder a validé
    
    
    	/**
    	 * Returns the array of new processed parameters once the parameters are applied.
    	 * For example: if you set range=last30 and date=2008-03-10, 
    	 *  the date element of the returned array will be "2008-02-10,2008-03-10"
    	 * 
    	 * Parameters you can set:
    	 * - range: last30, previous10, etc.
    	 * - date: YYYY-MM-DD, today, yesterday
    	 * - period: day, week, month, year
    	 * 
    	 * @param array  paramsToSet = array( 'date' => 'last50', 'viewDataTable' =>'sparkline' )
    	 */
    	protected function getGraphParamsModified($paramsToSet = array())
    	{
    		if(!isset($paramsToSet['range']))
    		{
    			$range = 'last30';
    		}
    		else
    		{
    			$range = $paramsToSet['range'];
    		}
    		
    		if(!isset($paramsToSet['date']))
    		{
    			$endDate = $this->strDate;
    		}
    		else
    		{
    			$endDate = $paramsToSet['date'];
    		}
    		
    		if(!isset($paramsToSet['period']))
    		{
    			$period = Piwik_Common::getRequestVar('period');
    		}
    		else
    		{
    			$period = $paramsToSet['period'];
    		}
    
    mattpiwik's avatar
    mattpiwik a validé
    		if(is_null($this->site))
    		{
    			throw new Piwik_Access_NoAccessException("Website not initialized, check that you are logged in and/or using the correct token_auth.");
    		}
    
    mattpiwik's avatar
    mattpiwik a validé
    		$last30Relative = new Piwik_Period_Range($period, $range, $this->site->getTimezone() );
    
    		
    		$last30Relative->setDefaultEndDate(Piwik_Date::factory($endDate));
    		
    		$paramDate = $last30Relative->getDateStart()->toString() . "," . $last30Relative->getDateEnd()->toString();
    		
    		$params = array_merge($paramsToSet , array(	'date' => $paramDate ) );
    		return $params;
    	}
    	
    	/**
    	 * Returns a numeric value from the API.
    	 * Works only for API methods that originally returns numeric values (there is no cast here)
    	 *
    	 * @param string $methodToCall, eg. Referers.getNumberOfDistinctSearchEngines
    	 * @return int|float
    	 */
    	protected function getNumericValue( $methodToCall )
    	{
    		$requestString = 'method='.$methodToCall.'&format=original';
    		$request = new Piwik_API_Request($requestString);
    		return $request->process();
    	}
    
    	/**
    
    	 * Returns the current URL to use in a img src=X to display a sparkline.
    
    	 * $action must be the name of a Controller method that requests data using the Piwik_ViewDataTable::factory
    	 * It will automatically build a sparkline by setting the viewDataTable=sparkline parameter in the URL.
    	 * It will also computes automatically the 'date' for the 'last30' days/weeks/etc. 
    	 *
    	 * @param string $action, eg. method name of the controller to call in the img src
    
    	 * @param array array of name => value of parameters to set in the generated GET url 
    
    	protected function getUrlSparkline( $action, $customParameters = array() )
    
    	{
    		$params = $this->getGraphParamsModified( 
    					array(	'viewDataTable' => 'sparkline', 
    							'action' => $action,
    							'module' => $this->pluginName)
    
    		// convert array values to comma separated
    		foreach($params as &$value)
    		{
    			if(is_array($value))
    			{
    				$value = implode(',', $value);
    			}
    		}
    
    		$url = Piwik_Url::getCurrentQueryStringWithParametersModified($params);
    		return $url;
    	}
    	
    
    mattpiwik's avatar
    mattpiwik a validé
    	/**
    	 * Sets the first date available in the calendar
    	 * @param $minDate
    	 * @param $view
    	 * @return void
    	 */
    
    mattpiwik's avatar
    mattpiwik a validé
    	protected function setMinDateView(Piwik_Date $minDate, $view)
    	{
    		$view->minDateYear = $minDate->toString('Y');
    		$view->minDateMonth = $minDate->toString('m');
    		$view->minDateDay = $minDate->toString('d');
    	}
    	
    
    mattpiwik's avatar
    mattpiwik a validé
    	/**
    	 * Sets "today" in the calendar. Today does not always mean "UTC" today, eg. for websites in UTC+12.
    	 * @param $maxDate
    	 * @param $view
    	 * @return void
    	 */
    	protected function setMaxDateView(Piwik_Date $maxDate, $view)
    	{
    		$view->maxDateYear = $maxDate->toString('Y');
    		$view->maxDateMonth = $maxDate->toString('m');
    		$view->maxDateDay = $maxDate->toString('d');
    	}
    	
    	/**
    
    	 * Sets general variables to the view that are used by various templates and Javascript.
    	 * If any error happens, displays the login screen
    
    mattpiwik's avatar
    mattpiwik a validé
    	 * @param $view
    	 * @return void
    	 */
    
    	protected function setGeneralVariablesView($view)
    	{
    		$view->date = $this->strDate;
    		
    		try {
    
    			$this->setPeriodVariablesView($view);
    
    mattpiwik's avatar
    mattpiwik a validé
    			
    			$date = Piwik_Date::factory($this->strDate); 
    			$view->prettyDate = Piwik_Period::factory(Piwik_Common::getRequestVar('period'), $date)->getPrettyString();
    
    mattpiwik's avatar
    mattpiwik a validé
    			$view->idSite = $this->idSite;
    			if(is_null($this->site))
    			{
    				throw new Exception("invalid website");
    			}
    			$view->siteName = $this->site->getName();
    			$view->siteMainUrl = $this->site->getMainUrl();
    
    mattpiwik's avatar
    mattpiwik a validé
    			$datetimeMinDate = $this->site->getCreationDate()->getDatetime();
    			$minDate = Piwik_Date::factory($datetimeMinDate, $this->site->getTimezone());
    
    mattpiwik's avatar
    mattpiwik a validé
    			$this->setMinDateView($minDate, $view);
    
    mattpiwik's avatar
    mattpiwik a validé
    			$maxDate = Piwik_Date::factory('now', $this->site->getTimezone());
    			$this->setMaxDateView($maxDate, $view);
    
    mattpiwik's avatar
    mattpiwik a validé
    			$this->setBasicVariablesView($view);
    
    			self::redirectToIndex( Piwik::getLoginPluginName(), $action = 'index' );
    
    mattpiwik's avatar
    mattpiwik a validé
    	/**
    	 * Will only set the minimal variables in the view object
    	 * Used by Admin screens
    	 * 
    	 * @param $view
    	 */
    
    robocoder's avatar
    robocoder a validé
    	protected function setBasicVariablesView($view)
    
    mattpiwik's avatar
    mattpiwik a validé
    	{
    		$view->topMenu = Piwik_GetTopMenu();
    		$view->currentAdminMenuName = Piwik_GetCurrentAdminMenuName();
    		$view->debugTrackVisitsInsidePiwikUI = Zend_Registry::get('config')->Debug->track_visits_inside_piwik_ui;
    
    		$view->isSuperUser = Zend_Registry::get('access')->isSuperUser();
    	}
    	
    
    mattpiwik's avatar
    mattpiwik a validé
    	/**
    	 * Sets general period variables (available periods, current period, period labels) used by templates 
    	 * @param $view
    	 * @return void
    	 */
    
    	public static function setPeriodVariablesView($view)
    
    		$currentPeriod = Piwik_Common::getRequestVar('period');
    
    		$availablePeriods = array('day', 'week', 'month', 'year');
    		if(!in_array($currentPeriod,$availablePeriods))
    		{
    			throw new Exception("Period must be one of: ".implode(",",$availablePeriods));
    		}
    		$periodNames = array(
    
    			'day' => array('singular' => Piwik_Translate('CoreHome_PeriodDay'), 'plural' => Piwik_Translate('CoreHome_PeriodDays')),
    			'week' => array('singular' => Piwik_Translate('CoreHome_PeriodWeek'), 'plural' => Piwik_Translate('CoreHome_PeriodWeeks')),
    			'month' => array('singular' => Piwik_Translate('CoreHome_PeriodMonth'), 'plural' => Piwik_Translate('CoreHome_PeriodMonths')),
    			'year' => array('singular' => Piwik_Translate('CoreHome_PeriodYear'), 'plural' => Piwik_Translate('CoreHome_PeriodYears')),
    
    		$found = array_search($currentPeriod,$availablePeriods);
    
    			unset($availablePeriods[$found]);
    
    		$view->otherPeriods = $availablePeriods;
    		$view->periodsNames = $periodNames;
    
    mattpiwik's avatar
    mattpiwik a validé
    	/**
    	 * Helper method used to redirect the current http request to another module/action
    	 * If specified, will also redirect to a given website, period and /or date
    	 * 
    	 * @param $moduleToRedirect eg. "MultiSites"
    	 * @param $actionToRedirect eg. "index"
    	 * @param $websiteId eg. 1
    	 * @param $defaultPeriod eg. "day"
    	 * @param $defaultDate eg. "today"
    	 * @return issues a http header redirect and exits
    	 */
    
    	function redirectToIndex($moduleToRedirect, $actionToRedirect, $websiteId = null, $defaultPeriod = null, $defaultDate = null)
    
    		if(is_null($websiteId))
    		{
    			$websiteId = $this->getDefaultWebsiteId();
    		}
    		if(is_null($defaultDate))
    		{
    			$defaultDate = $this->getDefaultDate();
    		}
    		if(is_null($defaultPeriod))
    		{
    			$defaultPeriod = $this->getDefaultPeriod();
    		}
    
    
    mattpiwik's avatar
    mattpiwik a validé
    		if($websiteId) {
    
    robocoder's avatar
    robocoder a validé
    			header("Location: index.php?module=".$moduleToRedirect
    
    mattpiwik's avatar
    mattpiwik a validé
    									."&action=".$actionToRedirect
    									."&idSite=".$websiteId
    									."&period=".$defaultPeriod
    									."&date=".$defaultDate);
    			exit;
    		}
    		
    		if(Piwik::isUserIsSuperUser())
    		{
    
    			Piwik_ExitWithMessage("Error: no website was found in this Piwik installation. 
    
    			<br />Check the table '". Piwik_Common::prefixTable('site') ."' that should contain your Piwik websites.", false, true);
    
    mattpiwik's avatar
    mattpiwik a validé
    		}
    		
    		$currentLogin = Piwik::getCurrentUserLogin();
    		if(!empty($currentLogin)
    			&& $currentLogin != 'anonymous')
    		{
    			$errorMessage = sprintf(Piwik_Translate('CoreHome_NoPrivileges'),$currentLogin);
    			$errorMessage .= "<br /><br />&nbsp;&nbsp;&nbsp;<b><a href='index.php?module=". Zend_Registry::get('auth')->getName() ."&amp;action=logout'>&rsaquo; ". Piwik_Translate('General_Logout'). "</a></b><br />";
    			Piwik_ExitWithMessage($errorMessage, false, true);
    		}
    
    
    		Piwik_FrontController::getInstance()->dispatch(Piwik::getLoginPluginName(), false);
    
    mattpiwik's avatar
     
    mattpiwik a validé
    		exit;
    
    mattpiwik's avatar
    mattpiwik a validé
    	}
    	
    
    	/**
    
    mattpiwik's avatar
    mattpiwik a validé
    	 * Returns default website that Piwik should load 
    
    mattpiwik's avatar
    mattpiwik a validé
    	 * @return Piwik_Site
    	 */
    	protected function getDefaultWebsiteId()
    	{
    		$defaultWebsiteId = false;
    
    	
    		// User preference: default website ID to load
    		$defaultReport = Piwik_UsersManager_API::getInstance()->getUserPreference(Piwik::getCurrentUserLogin(), Piwik_UsersManager_API::PREFERENCE_DEFAULT_REPORT);
    		if(is_numeric($defaultReport)) 
    		{
    			$defaultWebsiteId = $defaultReport;
    		}
    		
    
    mattpiwik's avatar
    mattpiwik a validé
    		Piwik_PostEvent( 'Controller.getDefaultWebsiteId', $defaultWebsiteId );
    		
    		if($defaultWebsiteId) 
    		{
    			return $defaultWebsiteId;
    		}
    		
    
    robocoder's avatar
    robocoder a validé
    		$sitesId = Piwik_SitesManager_API::getInstance()->getSitesIdWithAtLeastViewAccess();
    
    mattpiwik's avatar
    mattpiwik a validé
    			return $sitesId[0];
    
    mattpiwik's avatar
    mattpiwik a validé
    		return false;
    	}
    
    mattpiwik's avatar
    mattpiwik a validé
    	/**
    	 * Returns default date for Piwik reports
    	 * @return string today, 2010-01-01, etc.
    	 */
    
    mattpiwik's avatar
    mattpiwik a validé
    	protected function getDefaultDate()
    
    mattpiwik's avatar
    mattpiwik a validé
    	{
    
    		$userSettingsDate = Piwik_UsersManager_API::getInstance()->getUserPreference(Piwik::getCurrentUserLogin(), Piwik_UsersManager_API::PREFERENCE_DEFAULT_REPORT_DATE);
    		if($userSettingsDate === false)
    		{
    			return Zend_Registry::get('config')->General->default_day;
    		}
    		if($userSettingsDate == 'yesterday')
    		{
    			return $userSettingsDate;
    		}
    		return 'today';
    
    mattpiwik's avatar
    mattpiwik a validé
    	}
    	
    	/**
    
    	 * Returns default date for Piwik reports
    	 * @return string today, 2010-01-01, etc.
    
    mattpiwik's avatar
    mattpiwik a validé
    	 */
    	protected function getDefaultPeriod()
    	{
    
    		$userSettingsDate = Piwik_UsersManager_API::getInstance()->getUserPreference(Piwik::getCurrentUserLogin(), Piwik_UsersManager_API::PREFERENCE_DEFAULT_REPORT_DATE);
    		if($userSettingsDate === false)
    		{
    			return Zend_Registry::get('config')->General->default_period;
    		}
    		if(in_array($userSettingsDate, array('today','yesterday')))
    		{
    			return 'day';
    		}
    		return $userSettingsDate;
    
    	
    	/**
    	 * Checks that the specified token matches the current logged in user token
    	 * Protection against CSRF
    	 * 
    	 * @return throws exception if token doesn't match
    	 */
    	protected function checkTokenInUrl()
    	{
    		if(Piwik_Common::getRequestVar('token_auth', false) != Piwik::getCurrentUserTokenAuth()) {
    
    			throw new Piwik_Access_NoAccessException(Piwik_TranslateException('General_ExceptionInvalidToken'));
    
    mattpiwik's avatar
    mattpiwik a validé
    }