Ticket #708: 708.patch

File 708.patch, 49.3 KB (added by mauser, 2 years ago)
  • lang/en.php

     
    200200        'CoreUpdater_ExceptionArchiveIncomplete' => 'Archive is incomplete: some files are missing (eg. %s).', 
    201201        'Actions_Actions' => 'Actions', 
    202202        'Actions_SubmenuPages' => 'Pages', 
     203        'Actions_SubmenuPageTitles' => 'Page titles', 
    203204        'Actions_SubmenuOutlinks' => 'Outlinks', 
    204205        'Actions_SubmenuDownloads' => 'Downloads', 
    205206        'Actions_ColumnClicks' => 'Clicks', 
     
    207208        'Actions_ColumnDownloads' => 'Downloads', 
    208209        'Actions_ColumnUniqueDownloads' => 'Unique Downloads', 
    209210        'Actions_ColumnPageName' => 'Page Name', 
     211        'Actions_ColumnPageURL' => 'Page URL', 
    210212        'Actions_ColumnClickedURL' => 'Clicked URL', 
    211213        'Actions_ColumnDownloadURL' => 'Download URL', 
    212214        'Dashboard_Dashboard' => 'Dashboard', 
  • plugins/Actions/API.php

     
    5050                $dataTable->queueFilter('ReplaceSummaryRowLabel'); 
    5151                return $dataTable; 
    5252        } 
    53          
     53 
     54        /* 
     55         * Backward compatibility. Use getPageUrls() method instead. 
     56         */ 
    5457        public function getActions( $idSite, $period, $date, $expanded = false, $idSubtable = false ) 
    5558        { 
     59            return $this->getPageUrls( $idSite, $period, $date, $expanded, $idSubtable ); 
     60        } 
     61         
     62        public function getPageUrls( $idSite, $period, $date, $expanded = false, $idSubtable = false ) 
     63        { 
    5664                return $this->getDataTable('Actions_actions', $idSite, $period, $date, $expanded, $idSubtable ); 
    5765        } 
    5866 
     67        public function getPageTitles( $idSite, $period, $date, $expanded = false, $idSubtable = false) 
     68        { 
     69                $dataTable = $this->getDataTable('Actions_actions_name', $idSite, $period, $date, $expanded, $idSubtable); 
     70                return $dataTable; 
     71        } 
     72 
    5973        public function getDownloads( $idSite, $period, $date, $expanded = false, $idSubtable = false ) 
    6074        { 
    6175                $dataTable = $this->getDataTable('Actions_downloads', $idSite, $period, $date, $expanded, $idSubtable ); 
  • plugins/Actions/tests/Actions.test.php

     
     1<?php 
     2if(!defined("PIWIK_PATH_TEST_TO_ROOT")) { 
     3        define('PIWIK_PATH_TEST_TO_ROOT', getcwd().'/../../..'); 
     4} 
     5if(!defined('PIWIK_CONFIG_TEST_INCLUDED')) 
     6{ 
     7        require_once PIWIK_PATH_TEST_TO_ROOT . "/tests/config_test.php"; 
     8} 
     9 
     10require_once 'Actions/Actions.php'; 
     11require_once 'Tracker/Action.php'; 
     12require_once 'Tracker/Config.php'; 
     13 
     14class Test_Piwik_Actions extends UnitTestCase 
     15{ 
     16        function test_extractUrlAndActionNameFromRequest() 
     17        { 
     18                $userFile = PIWIK_INCLUDE_PATH . '/tests/resources/plugins/Actions/Actions.config.ini.php'; 
     19 
     20                Piwik::createConfigObject($userFile); 
     21 
     22                $action = new Test_Piwik_Actions_extractUrlAndActionNameFromRequest(); 
     23 
     24                $tests = array( 
     25                        array( 
     26                                'params' =>     array( 'name' => 'http://example.org/', 'type' => Piwik_Tracker_Action::TYPE_ACTION), 
     27                                'expected' => array('index' ), 
     28                        ), 
     29                        array( 
     30                                'params' =>     array( 'name' => 'http://example.org/path/', 'type' => Piwik_Tracker_Action::TYPE_ACTION), 
     31                                'expected' => array( 'path', 'index' ), 
     32                        ), 
     33                        array( 
     34                                'params' =>     array( 'name' => 'http://example.org/test/path', 'type' => Piwik_Tracker_Action::TYPE_ACTION), 
     35                                'expected' => array( 'test', 'path' ), 
     36                        ), 
     37                        array( 
     38                                'params' =>     array( 'name' => 'Test / Path', 'type' => Piwik_Tracker_Action::TYPE_ACTION), 
     39                                'expected' => array( 'Test', 'Path' ), 
     40                        ), 
     41                        array( 
     42                                'params' =>     array( 'name' => '    Test trim   ', 'type' => Piwik_Tracker_Action::TYPE_ACTION), 
     43                                'expected' => array( 'Test trim' ), 
     44                        ), 
     45                        array( 
     46                                'params' =>     array( 'name' => 'Category / Subcategory', 'type' => Piwik_Tracker_Action::TYPE_ACTION_NAME), 
     47                                'expected' => array( 'Category', 'Subcategory' ), 
     48                        ), 
     49                        array( 
     50                                'params' =>     array( 'name' => '/path/index.php?var=test', 'type' => Piwik_Tracker_Action::TYPE_ACTION_NAME), 
     51                                'expected' => array( 'path', 'index.php?var=test' ), 
     52                        ), 
     53                        array( 
     54                                'params' =>     array( 'name' => 'http://example.org/path/Default.aspx#anchor', 'type' => Piwik_Tracker_Action::TYPE_ACTION_NAME), 
     55                                'expected' => array( 'path', 'Default.aspx' ), 
     56                        ), 
     57                        array( 
     58                                'params' =>     array( 'name' => '', 'type' => Piwik_Tracker_Action::TYPE_ACTION_NAME), 
     59                                'expected' => array( 'index' ), 
     60                        ), 
     61                        array( 
     62                                'params' =>     array( 'name' => 'http://example.org/download.zip', 'type' => Piwik_Tracker_Action::TYPE_DOWNLOAD), 
     63                                'expected' => array( 'example.org', '/download.zip' ), 
     64                        ), 
     65                        array( 
     66                                'params' =>     array( 'name' => 'http://example.org/download/1/', 'type' => Piwik_Tracker_Action::TYPE_DOWNLOAD), 
     67                                'expected' => array( 'example.org', '/download/1/' ), 
     68                        ), 
     69                        array( 
     70                                'params' =>     array( 'name' => 'http://example.org/link', 'type' => Piwik_Tracker_Action::TYPE_OUTLINK), 
     71                                'expected' => array( 'example.org', '/link' ), 
     72                        ), 
     73                        array( 
     74                                'params' =>     array( 'name' => 'http://example.org/some/path/', 'type' => Piwik_Tracker_Action::TYPE_OUTLINK), 
     75                                'expected' => array( 'example.org', '/some/path/' ), 
     76                        ), 
     77 
     78                ); 
     79                foreach($tests as $test) { 
     80                        $params = $test['params']; 
     81                        $expected = $test['expected']; 
     82                        $this->assertEqual($action->public_getActionExplodedNames($params['name'],$params['type']), $expected); 
     83                } 
     84        } 
     85} 
     86 
     87class Test_Piwik_Actions_extractUrlAndActionNameFromRequest extends Piwik_Actions { 
     88        public function public_getActionExplodedNames($name, $type) 
     89        { 
     90                return self::getActionExplodedNames($name, $type); 
     91        } 
     92} 
     93 No newline at end of file 
  • plugins/Actions/Actions.php

     
    2020class Piwik_Actions extends Piwik_Plugin 
    2121{ 
    2222        static protected $actionCategoryDelimiter = null; 
     23        static protected $defaultActionName = null; 
    2324        static protected $limitLevelSubCategory = 10; // must be less than Piwik_DataTable::MAXIMUM_DEPTH_LEVEL_ALLOWED 
    2425        protected $maximumRowsInDataTableLevelZero; 
    2526        protected $maximumRowsInSubDataTable; 
     
    5051        public function __construct() 
    5152        { 
    5253                self::$actionCategoryDelimiter =  Zend_Registry::get('config')->General->action_category_delimiter; 
     54                self::$defaultActionName = Zend_Registry::get('config')->Tracker->default_action_name; 
    5355                $this->columnToSortByBeforeTruncation = 'nb_visits'; 
    5456                $this->maximumRowsInDataTableLevelZero = Zend_Registry::get('config')->General->datatable_archiving_maximum_rows_actions; 
    5557                $this->maximumRowsInSubDataTable = Zend_Registry::get('config')->General->datatable_archiving_maximum_rows_subtable_actions; 
     
    5759         
    5860        function addWidgets() 
    5961        { 
    60                 Piwik_AddWidget( 'Actions_Actions', 'Actions_SubmenuPages', 'Actions', 'getActions'); 
     62                Piwik_AddWidget( 'Actions_Actions', 'Actions_SubmenuPages', 'Actions', 'getPageUrls'); 
     63                Piwik_AddWidget( 'Actions_Actions', 'Actions_SubmenuPageTitles', 'Actions', 'getPageTitles'); 
    6164                Piwik_AddWidget( 'Actions_Actions', 'Actions_SubmenuOutlinks', 'Actions', 'getOutlinks'); 
    6265                Piwik_AddWidget( 'Actions_Actions', 'Actions_SubmenuDownloads', 'Actions', 'getDownloads'); 
    6366        } 
    6467         
    6568        function addMenus() 
    6669        { 
    67                 Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuPages', array('module' => 'Actions', 'action' => 'getActions')); 
     70                Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuPages', array('module' => 'Actions', 'action' => 'getPageUrls')); 
     71                Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuPageTitles', array('module' => 'Actions', 'action' => 'getPageTitles')); 
    6872                Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuOutlinks', array('module' => 'Actions', 'action' => 'getOutlinks')); 
    69                 Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuDownloads', array('module' => 'Actions', 'action' => 'getDownloads'));          
     73                Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuDownloads', array('module' => 'Actions', 'action' => 'getDownloads')); 
    7074        } 
    7175         
    7276        static protected $invalidSummedColumnNameToRenamedNameForPeriodArchive = array( 
     
    8892                                'Actions_actions', 
    8993                                'Actions_downloads', 
    9094                                'Actions_outlink', 
     95                                'Actions_actions_name', 
    9196                ); 
    9297                $archiveProcessing->archiveDataTable($dataTableToSum, self::$invalidSummedColumnNameToRenamedNameForPeriodArchive, $this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable, $this->columnToSortByBeforeTruncation); 
    9398        } 
     
    109114                        Piwik_Tracker_Action::TYPE_ACTION => array(), 
    110115                        Piwik_Tracker_Action::TYPE_DOWNLOAD => array(), 
    111116                        Piwik_Tracker_Action::TYPE_OUTLINK => array(), 
     117                        Piwik_Tracker_Action::TYPE_ACTION_NAME => array(), 
    112118                ); 
    113119                 
    114120                // This row is used in the case where an action is know as an exit_action 
     
    122128                                                                                ))); 
    123129 
    124130                /* 
    125                  * Actions global information 
     131                 * Actions urls global information 
    126132                 */ 
    127133                $query = "SELECT        name, 
    128134                                                        type, 
     
    131137                                                        count(*) as nb_hits                                                      
    132138                                        FROM (".$archiveProcessing->logTable." as t1 
    133139                                                LEFT JOIN ".$archiveProcessing->logVisitActionTable." as t2 USING (idvisit)) 
    134                                                         LEFT JOIN ".$archiveProcessing->logActionTable." as t3 USING (idaction) 
     140                                                        LEFT JOIN ".$archiveProcessing->logActionTable." as t3 ON (t2.idaction_url = t3.idaction) 
    135141                                        WHERE visit_server_date = ? 
    136142                                                AND idsite = ? 
    137143                                        GROUP BY t3.idaction 
     
    139145                $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite )); 
    140146                $modified = $this->updateActionsTableWithRowQuery($query); 
    141147 
    142                  
    143148                /* 
     149                 * Actions names global information 
     150                 */ 
     151                $query = "SELECT        name, 
     152                                                        type, 
     153                                                        count(distinct t1.idvisit) as nb_visits, 
     154                                                        count(distinct visitor_idcookie) as nb_uniq_visitors, 
     155                                                        count(*) as nb_hits 
     156                                        FROM (".$archiveProcessing->logTable." as t1 
     157                                                LEFT JOIN ".$archiveProcessing->logVisitActionTable." as t2 USING (idvisit)) 
     158                                                        LEFT JOIN ".$archiveProcessing->logActionTable." as t3 ON (t2.idaction_name = t3.idaction) 
     159                                        WHERE visit_server_date = ? 
     160                                                AND idsite = ? 
     161                                        GROUP BY t3.idaction 
     162                                        ORDER BY nb_hits DESC"; 
     163                $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite )); 
     164                $modified = $this->updateActionsTableWithRowQuery($query); 
     165 
     166                /* 
    144167                 * Entry actions 
    145168                 */ 
    146169                $query = "SELECT        name, 
     
    151174                                                        sum(visit_total_time) as entry_sum_visit_length,                                                         
    152175                                                        sum(case visit_total_actions when 1 then 1 else 0 end) as entry_bounce_count 
    153176                                        FROM ".$archiveProcessing->logTable."  
    154                                                 JOIN ".$archiveProcessing->logActionTable." ON (visit_entry_idaction = idaction) 
     177                                                JOIN ".$archiveProcessing->logActionTable." ON (visit_entry_idaction_url = idaction) 
    155178                                        WHERE visit_server_date = ? 
    156179                                                AND idsite = ? 
    157                                         GROUP BY visit_entry_idaction 
     180                                        GROUP BY visit_entry_idaction_url 
    158181                                        "; 
    159182                $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite )); 
    160183                $modified = $this->updateActionsTableWithRowQuery($query); 
     
    169192                                                        count(*) as exit_nb_visits, 
    170193                                                        sum(case visit_total_actions when 1 then 1 else 0 end) as exit_bounce_count 
    171194                                        FROM ".$archiveProcessing->logTable."  
    172                                                 JOIN ".$archiveProcessing->logActionTable." ON (visit_exit_idaction = idaction) 
     195                                                JOIN ".$archiveProcessing->logActionTable." ON (visit_exit_idaction_url = idaction) 
    173196                                        WHERE visit_server_date = ? 
    174197                                                AND idsite = ? 
    175                                         GROUP BY visit_exit_idaction 
     198                                        GROUP BY visit_exit_idaction_url 
    176199                                        "; 
    177200                $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite )); 
    178201                $modified = $this->updateActionsTableWithRowQuery($query); 
     
    185208                                                        sum(time_spent_ref_action) as sum_time_spent 
    186209                                        FROM (".$archiveProcessing->logTable." log_visit  
    187210                                                JOIN ".$archiveProcessing->logVisitActionTable." log_link_visit_action USING (idvisit)) 
    188                                                         JOIN ".$archiveProcessing->logActionTable."  log_action ON (log_action.idaction = log_link_visit_action.idaction_ref)                                    
     211                                                        JOIN ".$archiveProcessing->logActionTable."  log_action ON (log_action.idaction = log_link_visit_action.idaction_url_ref) 
    189212                                        WHERE visit_server_date = ? 
    190213                                                AND idsite = ? 
    191                                         GROUP BY idaction_ref 
     214                                        GROUP BY idaction_url_ref 
    192215                                "; 
    193216                $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite )); 
    194217                $modified = $this->updateActionsTableWithRowQuery($query); 
     
    215238                $archiveProcessing->insertBlobRecord('Actions_outlink', $s); 
    216239                destroy($dataTable); 
    217240 
     241                $dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_ACTION_NAME]); 
     242                $this->deleteInvalidSummedColumnsFromDataTable($dataTable); 
     243                $s = $dataTable->getSerialized( $this->maximumRowsInDataTableLevelZero, $this->maximumRowsInSubDataTable, $this->columnToSortByBeforeTruncation ); 
     244                $archiveProcessing->insertBlobRecord('Actions_actions_name', $s); 
     245                destroy($dataTable); 
     246 
    218247                unset($this->actionsTablesByType); 
    219248        } 
    220249         
     
    232261                        } 
    233262                } 
    234263        } 
     264         
     265        /** 
     266         * Explodes action name into an array of elements. 
     267         * 
     268         * for downloads: 
     269         *  we explode link http://piwik.org/some/path/piwik.zip into an array( 'piwik.org', '/some/path/piwik.zip' ); 
     270         * 
     271         * for outlinks: 
     272         *  we explode link http://dev.piwik.org/some/path into an array( 'dev.piwik.org', '/some/path' ); 
     273         * 
     274         * for action urls: 
     275         *  we explode link http://piwik.org/some/path into an array( 'some', 'path' ); 
     276         * 
     277         * for action names: 
     278         *   we explode name 'Piwik / Category 1 / Category 2' into an array('Piwik', 'Category 1', 'Category 2'); 
     279         * 
     280         * @param string action name 
     281         * @param int action type 
     282         * @return array of exploded elements from $name 
     283         */ 
    235284        static public function getActionExplodedNames($name, $type) 
    236285        { 
     286                $matches = array(); 
     287                $isUrl = false; 
     288                 
     289                preg_match('@^http[s]?://([^/]+)[/]?([^#]*)[#]?(.*)$@i', $name, $matches); 
     290 
     291                if( count($matches) ) 
     292                { 
     293                        $isUrl = true; 
     294                        $urlHost = $matches[1]; 
     295                        $urlPath = $matches[2]; 
     296                        $urlAnchor = $matches[3]; 
     297                } 
     298                 
    237299                if($type == Piwik_Tracker_Action::TYPE_DOWNLOAD 
    238300                        || $type == Piwik_Tracker_Action::TYPE_OUTLINK) 
    239301                { 
    240                         $matches = $split_arr = array(); 
    241                         //TODO optimize with substring count rather than preg_match 
    242                         if(preg_match("#://[^/]+(/)#", $name, $matches, PREG_OFFSET_CAPTURE)) 
     302                        if( $isUrl ) 
    243303                        { 
    244                                 $host = substr($name, 0, $matches[1][1]); 
    245                                 return array($host, substr($name, strlen($host))); 
     304                                return array($urlHost, '/' . $urlPath); 
    246305                        } 
    247                         return array($name, "/"); 
    248306                } 
     307 
     308                if( $isUrl ) 
     309                { 
     310                        $name = $urlPath; 
     311                         
     312                        if( empty($name) || substr($name, -1) == '/' ) 
     313                        { 
     314                                $name .= self::$defaultActionName; 
     315                        } 
     316                } 
     317                 
    249318                if(empty(self::$actionCategoryDelimiter)) 
    250319                { 
    251                         return array($name); 
     320                        return array( trim($name) ); 
    252321                } 
    253                 return explode( self::$actionCategoryDelimiter,  
    254                                                 $name,  
    255                                                 self::$limitLevelSubCategory); 
     322 
     323                $split = explode(self::$actionCategoryDelimiter, $name, self::$limitLevelSubCategory); 
     324 
     325                // trim every category and remove empty categories 
     326                $split = array_map('trim', $split); 
     327                $split = array_filter($split); 
     328 
     329                if( empty($split) ) 
     330                { 
     331                        return array( self::$defaultActionName ); 
     332                } 
     333 
     334                return array_values( $split ); 
    256335        } 
    257336         
    258          
    259337        protected function updateActionsTableWithRowQuery($query) 
    260338        { 
    261339                $rowsProcessed = 0; 
     
    265343 
    266344                        // we work on the root table of the given TYPE (either ACTION or DOWNLOAD or OUTLINK etc.) 
    267345                        $currentTable =& $this->actionsTablesByType[$row['type']]; 
    268                          
     346 
    269347                        // go to the level of the subcategory 
    270348                        $end = count($actionExplodedNames)-1; 
    271349                        for($level = 0 ; $level < $end; $level++) 
     
    274352                                $currentTable =& $currentTable[$actionCategory]; 
    275353                        } 
    276354                        $actionName = $actionExplodedNames[$end]; 
    277                          
    278                         // we are careful to prefix the pageName with some value  
     355 
     356                        // we are careful to prefix the page URL / name with some value 
    279357                        // so that if a page has the same name as a category  
    280358                        // we don't merge both entries  
    281                         if($row['type'] == Piwik_Tracker_Action::TYPE_ACTION) 
     359                        if($row['type'] == Piwik_Tracker_Action::TYPE_ACTION ) 
    282360                        { 
    283361                                $actionName = '/' . $actionName; 
    284362                        } 
    285                                                  
     363                        else if( $row['type'] == Piwik_Tracker_Action::TYPE_ACTION_NAME ) 
     364                        { 
     365                                $actionName = ' ' . $actionName; 
     366                        } 
     367 
    286368                        // currentTable is now the array element corresponding the the action 
    287369                        // at this point we may be for example at the 4th level of depth in the hierarchy 
    288370                        $currentTable =& $currentTable[$actionName]; 
     
    290372                        // add the row to the matching sub category subtable 
    291373                        if(!($currentTable instanceof Piwik_DataTable_Row)) 
    292374                        { 
    293                                 $currentTable = new Piwik_DataTable_Row(array(   
     375                                if( $row['type'] == Piwik_Tracker_Action::TYPE_ACTION_NAME ) 
     376                                { 
     377                                        $currentTable = new Piwik_DataTable_Row(array( 
    294378                                                        Piwik_DataTable_Row::COLUMNS => array('label' => (string)$actionName), 
     379                                                ));      
     380                                } 
     381                                else 
     382                                { 
     383                                        $currentTable = new Piwik_DataTable_Row(array( 
     384                                                        Piwik_DataTable_Row::COLUMNS => array('label' => (string)$actionName), 
    295385                                                        Piwik_DataTable_Row::METADATA => array('url' => (string)$row['name']), 
    296386                                                )); 
     387                                } 
    297388                        } 
    298389                         
    299390                        foreach($row as $name => $value) 
     
    325416                        if($currentTable->getColumn('nb_hits') === false) 
    326417                        { 
    327418                                // to test this code: delete the entries in log_link_action_visit for 
    328                                 //  a given exit_idaction  
     419                                //  a given exit_idaction_url 
    329420                                foreach($this->defaultRow->getColumns() as $name => $value) 
    330421                                { 
    331422                                        $currentTable->addColumn($name, $value); 
  • plugins/Actions/Controller.php

     
    1717 */ 
    1818class Piwik_Actions_Controller extends Piwik_Controller  
    1919{ 
    20         public function index() 
     20        public function getPageUrls($fetch = false) 
    2121        { 
    22                 $view = Piwik_View::factory('index'); 
    23                  
    24                 /* Actions, Downloads, Outlinks */ 
    25                 $view->dataTableActions = $this->getActions( true ); 
    26                 $view->dataTableDownloads = $this->getDownloads( true ); 
    27                 $view->dataTableOutlinks = $this->getOutlinks( true ); 
    28                  
    29                 echo $view->render(); 
     22                $view = Piwik_ViewDataTable::factory(); 
     23                $view->init(    $this->pluginName,  
     24                                                __FUNCTION__, 
     25                                                'Actions.getPageUrls', 
     26                                                'getPageUrlsSubDataTable' ); 
     27                $view->setColumnTranslation('label', Piwik_Translate('Actions_ColumnPageURL')); 
     28                $this->configureViewActions($view); 
     29                return $this->renderView($view, $fetch); 
    3030        } 
    3131         
    32         public function getActions($fetch = false) 
     32        public function getPageUrlsSubDataTable($fetch = false) 
    3333        { 
    3434                $view = Piwik_ViewDataTable::factory(); 
    3535                $view->init(    $this->pluginName,  
    3636                                                __FUNCTION__, 
    37                                                 'Actions.getActions',  
    38                                                 'getActionsSubDataTable' ); 
     37                                                'Actions.getPageUrls', 
     38                                                'getActionsSubDataTable'  ); 
    3939                $this->configureViewActions($view); 
     40                return $this->renderView($view, $fetch); 
     41        } 
     42 
     43        public function getPageTitles($fetch = false) 
     44        { 
     45                $view = Piwik_ViewDataTable::factory(); 
     46                $view->init(    $this->pluginName, 
     47                                                __FUNCTION__, 
     48                                                'Actions.getPageTitles', 
     49                                                'getPageTitlesSubDataTable' ); 
    4050                $view->setColumnTranslation('label', Piwik_Translate('Actions_ColumnPageName')); 
     51                $this->configureViewActions($view); 
    4152                return $this->renderView($view, $fetch); 
    4253        } 
    43          
    44         public function getActionsSubDataTable($fetch = false) 
     54 
     55        public function getPageTitlesSubDataTable($fetch = false) 
    4556        { 
    4657                $view = Piwik_ViewDataTable::factory(); 
    47                 $view->init(    $this->pluginName,  
     58                $view->init(    $this->pluginName, 
    4859                                                __FUNCTION__, 
    49                                                 'Actions.getActions',  
    50                                                 'getActionsSubDataTable'  ); 
     60                                                'Actions.getPageTitles', 
     61                                                'getPageTitlesSubDataTable'  ); 
    5162                $this->configureViewActions($view); 
    5263                return $this->renderView($view, $fetch); 
    5364        } 
    54          
     65 
    5566        public function getDownloads($fetch = false) 
    5667        { 
    5768                $view = Piwik_ViewDataTable::factory(); 
     
    7687                $view->disableSearchBox(); 
    7788                return $this->renderView($view, $fetch); 
    7889        } 
    79          
     90 
    8091        public function getOutlinks($fetch = false) 
    8192        { 
    8293                $view = Piwik_ViewDataTable::factory(); 
     
    101112                $view->disableSearchBox(); 
    102113                return $this->renderView($view, $fetch); 
    103114        } 
    104          
     115 
    105116        protected function configureViewActions($view) 
    106117        { 
    107118                $view->setTemplate('CoreHome/templates/datatable_actions.tpl'); 
     
    123134                 
    124135                $view->setLimit( 100 ); 
    125136                $view->setColumnsToDisplay( array('label','nb_hits','nb_visits') ); 
    126                 $view->setColumnTranslation('label', Piwik_Translate('Actions_ColumnPageName')); 
    127137                $view->setColumnTranslation('nb_hits', Piwik_Translate('General_ColumnPageviews')); 
    128138                $view->setColumnTranslation('nb_visits', Piwik_Translate('General_ColumnUniquePageviews')); 
    129139 
     
    171181                $view->disableExcludeLowPopulation(); 
    172182                $view->setLimit( 15 ); 
    173183        } 
    174          
     184 
    175185        protected function getArrayFromRecursiveDataTable( $dataTable, $depth = 0 ) 
    176186        { 
    177187                $table = array(); 
  • web.config

     
    1 <?xml version="1.0" encoding="UTF-8"?> 
    2 <configuration> 
    3   <system.webServer> 
    4     <security> 
    5       <requestFiltering> 
    6         <hiddenSegments> 
    7           <add segment="config" /> 
    8           <add segment="tmp" /> 
    9         </hiddenSegments> 
    10       </requestFiltering> 
    11     </security> 
    12     <directoryBrowse enabled="false" /> 
    13     <defaultDocument> 
    14       <files> 
    15         <remove value="index.php" /> 
    16         <add value="index.php" /> 
    17       </files> 
    18     </defaultDocument> 
    19   </system.webServer> 
    20 </configuration> 
  • core/Tracker/Action.php

     
    2121        const TYPE_ACTION   = 1; 
    2222        const TYPE_OUTLINK  = 2; 
    2323        const TYPE_DOWNLOAD = 3; 
     24        const TYPE_ACTION_NAME = 4; 
    2425         
    2526        public function setRequest($requestArray); 
    2627        public function setIdSite( $idSite ); 
     
    2930        public function getActionName(); 
    3031        public function getActionType(); 
    3132        public function record( $idVisit, $idRefererAction, $timeSpentRefererAction ); 
    32         public function getIdAction(); 
     33        public function getIdActionUrl(); 
     34        public function getIdActionName(); 
    3335        public function getIdLinkVisitAction(); 
    3436} 
    3537 
     
    4446 * - An action is defined by a name. 
    4547 * - The name can be specified in the JS Code in the variable 'action_name' 
    4648 *    For example you can decide to use the javascript value document.title as an action_name 
    47  * - If the name is not specified, we use the URL(path+query) to build a default name. 
    48  *    For example for "http://piwik.org/test/my_page/test.html"  
    49  *    the name would be "test/my_page/test.html" 
    50  * - If the name is empty we set it to default_action_name found in global.ini.php 
     49 * - If the URL was not passed to piwik, it uses default_action_url defined in global.ini 
    5150 * - Handling UTF8 in the action name 
    5251 * PLUGIN_IDEA - An action is associated to URLs and link to the URL from the reports (currently actions do not link to the url of the pages) 
    5352 * PLUGIN_IDEA - An action hit by a visitor is associated to the HTML title of the page that triggered the action and this HTML title is displayed in the interface 
     
    6059        private $request; 
    6160        private $idSite; 
    6261        private $idLinkVisitAction; 
    63         private $idAction = null; 
     62        private $idActionName = null; 
     63        private $idActionUrl = null; 
    6464 
    6565        private $actionName; 
    6666        private $actionType; 
    67         private $url; 
     67        private $actionUrl; 
    6868         
    6969        protected function getDefaultActionName() 
    7070        { 
    7171                return Piwik_Tracker_Config::getInstance()->Tracker['default_action_name']; 
    7272        } 
     73 
     74        protected function getDefaultActionUrl() 
     75        { 
     76                return Piwik_Tracker_Config::getInstance()->Tracker['default_action_url']; 
     77        } 
    7378         
    7479        public function setRequest($requestArray) 
    7580        { 
     
    9297        { 
    9398                return $this->actionType; 
    9499        } 
     100        public function getActionNameType() 
     101        { 
     102                $actionNameType = null; 
     103 
     104                // we can add here action types for names of other actions than page views (like downloads, outlinks) 
     105                switch( $this->getActionType() ) 
     106                { 
     107                        case Piwik_Tracker_Action_Interface::TYPE_ACTION: 
     108                                $actionNameType = Piwik_Tracker_Action_Interface::TYPE_ACTION_NAME; 
     109                                break; 
     110                } 
     111 
     112                return $actionNameType; 
     113        } 
     114 
     115        public function getIdActionUrl() 
     116        { 
     117                return $this->idActionUrl; 
     118        } 
     119        public function getIdActionName() 
     120        { 
     121                return $this->idActionName; 
     122        } 
    95123         
    96124        protected function setActionName($name) 
    97125        { 
     
    115143        } 
    116144         
    117145        /** 
    118          * Returns the idaction of the current action name. 
    119          * This idaction is used in the visitor logging table to link the visit information  
     146         * Loads the idaction of the current action name and the current action url. 
     147         * These idactions are used in the visitor logging table to link the visit information 
    120148         * (entry action, exit action) to the actions. 
    121          * This idaction is also used in the table that links the visits and their actions. 
     149         * These idactions are also used in the table that links the visits and their actions. 
    122150         *  
    123          * The methods takes care of creating a new record in the action table if the existing  
    124          * action name doesn't exist yet. 
     151         * The methods takes care of creating a new record(s) in the action table if the existing 
     152         * action name and action url doesn't exist yet. 
    125153         *  
    126          * @return int Id action that is associated to this action name in the Actions table lookup 
    127154         */ 
    128         function getIdAction() 
     155        function loadIdActionNameAndUrl() 
    129156        { 
    130                 if(!is_null($this->idAction)) 
     157                if( !is_null($this->idActionUrl) && !is_null($this->idActionName) ) 
    131158                { 
    132                         return $this->idAction; 
     159                        return; 
    133160                } 
    134                 $idAction = Piwik_Tracker::getDatabase()->fetch("/* SHARDING_ID_SITE = ".$this->idSite." */     SELECT idaction  
     161                $idAction = Piwik_Tracker::getDatabase()->fetchAll("/* SHARDING_ID_SITE = ".$this->idSite." */ 
     162                                                        SELECT idaction, type  
    135163                                                        FROM ".Piwik_Common::prefixTable('log_action') 
    136                                                 ."  WHERE name = ? AND type = ?",  
    137                                                 array($this->getActionName(), $this->getActionType())  
     164                                                ."  WHERE " 
     165                                                ."              ( hash = CRC32(?) AND name = ? AND type = ? ) " 
     166                                                ."      OR " 
     167                                                ."              ( hash = CRC32(?) AND name = ? AND type = ? ) ", 
     168                                                array($this->getActionName(), $this->getActionName(), $this->getActionNameType(), 
     169                                                        $this->getActionUrl(), $this->getActionUrl(), $this->getActionType()) 
    138170                                        ); 
    139                  
    140                 // the action name has not been found, create it 
    141                 if($idAction === false || $idAction == '') 
     171 
     172                if( $idAction !== false ) 
    142173                { 
    143                         Piwik_Tracker::getDatabase()->query("/* SHARDING_ID_SITE = ".$this->idSite." */ 
    144                                                         INSERT INTO ". Piwik_Common::prefixTable('log_action'). " ( name, type )  
    145                                                         VALUES (?,?)", 
    146                                                 array($this->getActionName(),$this->getActionType()) 
    147                                         ); 
    148                         $idAction = Piwik_Tracker::getDatabase()->lastInsertId(); 
     174                        foreach($idAction as $row) 
     175                        { 
     176                                if( $row['type'] == Piwik_Tracker_Action_Interface::TYPE_ACTION_NAME ) 
     177                                { 
     178                                        $this->idActionName = $row['idaction']; 
     179                                } 
     180                                else 
     181                                { 
     182                                        $this->idActionUrl = $row['idaction']; 
     183                                } 
     184                        } 
    149185                } 
    150                 else 
     186 
     187                $sql = "/* SHARDING_ID_SITE = ".$this->idSite." */  
     188                                                        INSERT INTO ". Piwik_Common::prefixTable('log_action').  
     189                                                        "( name, hash, type ) VALUES (?,CRC32(?),?)"; 
     190         
     191                if( is_null($this->idActionName) && !is_null($this->getActionName()) && !is_null($this->getActionNameType()) ) 
    151192                { 
    152                         $idAction = $idAction['idaction']; 
     193                        Piwik_Tracker::getDatabase()->query($sql, 
     194                                array($this->getActionName(), $this->getActionName(), $this->getActionNameType())); 
     195                        $this->idActionName = Piwik_Tracker::getDatabase()->lastInsertId(); 
    153196                } 
    154                 $this->idAction = $idAction; 
    155                 return $this->idAction; 
     197 
     198                if( is_null($this->idActionUrl) ) 
     199                { 
     200                        Piwik_Tracker::getDatabase()->query($sql, 
     201                                array($this->getActionUrl(), $this->getActionUrl(), $this->getActionType())); 
     202                        $this->idActionUrl = Piwik_Tracker::getDatabase()->lastInsertId(); 
     203                } 
    156204        } 
    157205         
    158206        /** 
     
    174222         */ 
    175223         public function record( $idVisit, $idRefererAction, $timeSpentRefererAction) 
    176224         { 
    177                 Piwik_Tracker::getDatabase()->query("/* SHARDING_ID_SITE = ".$this->idSite." */ INSERT INTO ".Piwik_Common::prefixTable('log_link_visit_action') 
    178                                                 ." (idvisit, idaction, idaction_ref, time_spent_ref_action) VALUES (?,?,?,?)", 
    179                                         array($idVisit, $this->getIdAction(), $idRefererAction, $timeSpentRefererAction) 
     225                $this->loadIdActionNameAndUrl(); 
     226 
     227                Piwik_Tracker::getDatabase()->query("/* SHARDING_ID_SITE = ".$this->idSite." */ INSERT INTO ".Piwik_Common::prefixTable('log_link_visit_action') 
     228                                                ." (idvisit, idaction_url, idaction_name, idaction_url_ref, time_spent_ref_action) VALUES (?,?,?,?,?)", 
     229                                        array($idVisit, $this->getIdActionUrl(), $this->getIdActionName(), $idRefererAction, $timeSpentRefererAction) 
    180230                                        ); 
    181231                 
    182232                $this->idLinkVisitAction = Piwik_Tracker::getDatabase()->lastInsertId();  
     
    209259         /** 
    210260         * Generates the name of the action from the URL or the specified name. 
    211261         * Sets the name as $this->actionName 
     262          * 
     263         * @return array 
    212264         */ 
    213265        protected function extractUrlAndActionNameFromRequest() 
    214266        { 
     267                $actionName = null; 
     268                 
    215269                // download? 
    216270                $downloadUrl = Piwik_Common::getRequestVar( 'download', '', 'string', $this->request); 
    217271                if(!empty($downloadUrl)) 
     
    230284                                $url = $outlinkUrl; 
    231285                        } 
    232286                } 
    233                  
     287 
     288                $actionName = Piwik_Common::getRequestVar( 'action_name', '', 'string', $this->request); 
     289 
    234290                // defaults to page view  
    235291                if(empty($actionType)) 
    236292                { 
    237293                        $actionType = self::TYPE_ACTION; 
    238294                        $url = Piwik_Common::getRequestVar( 'url', '', 'string', $this->request); 
    239                         $actionName = Piwik_Common::getRequestVar( 'action_name', '', 'string', $this->request); 
    240                         if( empty($actionName) ) 
     295 
     296                        if( empty($url) ) 
    241297                        { 
    242                                 $cleanedUrl = str_replace(array("\n", "\r", "\t"), "", $url); 
    243                                 $actionName = Piwik_Common::getPathAndQueryFromUrl($cleanedUrl); 
    244                                 // in case the $actionName is empty or ending with a slash,  
    245                                 // we append the defaultActionName: a/b/ becomes a/b/index  
    246                                 if(empty($actionName) 
    247                                         || substr($actionName, -1) == '/') 
    248                                 { 
    249                                         $actionName .= $this->getDefaultActionName(); 
    250                                 } 
     298                            $url .= $this->getDefaultActionUrl(); 
    251299                        } 
    252300                         
    253301                        // get the delimiter, by default '/' 
     
    268316                 
    269317                $url = trim($url); 
    270318                $url = str_replace(array("\n", "\r"), "", $url); 
    271                 if(empty($actionName)) 
    272                 { 
    273                         $actionName = $url; 
    274                 } 
    275319 
     320                $actionName = trim($actionName); 
     321                $actionName = str_replace(array("\n", "\r"), "", $actionName); 
     322 
    276323                return array( 
    277                         'name' => $actionName, 
     324                        'name' => empty($actionName) ? null : $actionName, 
    278325                        'type' => $actionType, 
    279326                        'url'  => $url, 
    280327                ); 
  • core/Tracker/GoalManager.php

     
    1717class Piwik_Tracker_GoalManager  
    1818{ 
    1919        /** 
    20          * @var Piwik_Cookie  
     20         * @var Piwik_Cookie 
    2121         */ 
    2222        protected $cookie = null; 
    2323        /** 
     
    4141                } 
    4242                return array(); 
    4343        } 
    44          
     44 
    4545        static public function getGoalDefinition( $idSite, $idGoal ) 
    4646        { 
    4747                $goals = self::getGoalDefinitions( $idSite ); 
     
    5454                } 
    5555                throw new Exception("The goal id = $idGoal couldn't be found."); 
    5656        } 
    57          
     57 
    5858        static public function getGoalIds( $idSite ) 
    5959        { 
    6060                $goals = self::getGoalDefinitions( $idSite ); 
     
    6565                } 
    6666                return $goalIds; 
    6767        } 
    68          
     68 
    6969        private function isGoalPluginEnabled() 
    7070        { 
    7171                return Piwik_PluginsManager::getInstance()->isPluginActivated('Goals'); 
    7272        } 
    73          
    74         //TODO does this code work for manually triggered goals, with custom revenue?  
     73 
     74        //TODO does this code work for manually triggered goals, with custom revenue? 
    7575        function detectGoalsMatchingUrl($idSite, $action) 
    7676        { 
    7777                if(!$this->isGoalPluginEnabled()) 
     
    9393                        { 
    9494                                continue; 
    9595                        } 
    96                          
     96 
    9797                        $pattern_type = $goal['pattern_type']; 
    98                          
     98 
    9999                        switch($pattern_type) 
    100100                        { 
    101101                                case 'regex': 
     
    141141//              var_dump($this->convertedGoals);exit; 
    142142                return count($this->convertedGoals) > 0; 
    143143        } 
    144          
     144 
    145145        function detectGoalId($idSite, $idGoal, $request) 
    146146        { 
    147147                if(!$this->isGoalPluginEnabled()) 
     
    159159                $this->convertedGoals[] = $goal; 
    160160                return true; 
    161161        } 
    162          
     162 
    163163        function recordGoals($visitorInformation, $action) 
    164164        { 
    165165                $location_country = isset($visitorInformation['location_country']) ? $visitorInformation['location_country'] : Piwik_Common::getCountry(Piwik_Common::getBrowserLanguage(), $enableLanguageToCountryGuess = Piwik_Tracker_Config::getInstance()->Tracker['enable_language_to_country_guess']); 
    166166                $location_continent = isset($visitorInformation['location_continent']) ? $visitorInformation['location_continent'] : Piwik_Common::getContinent($location_country); 
    167                  
     167 
    168168                $goal = array( 
    169169                        'idvisit'                       => $visitorInformation['idvisit'], 
    170170                        'idsite'                        => $visitorInformation['idsite'], 
     
    197197                        $newGoal['revenue'] = $convertedGoal['revenue']; 
    198198                        if(!is_null($action)) 
    199199                        { 
    200                                 $newGoal['idaction'] = $action->getIdAction(); 
     200                                $newGoal['idaction_url'] = $action->getIdActionUrl(); 
    201201                                $newGoal['idlink_va'] = $action->getIdLinkVisitAction(); 
    202202                        } 
    203203                        printDebug($newGoal); 
    204                          
     204 
    205205                        $fields = implode(", ", array_keys($newGoal)); 
    206206                        $bindFields = substr(str_repeat( "?,",count($newGoal)),0,-1); 
    207                          
     207 
    208208                        try { 
    209209                                Piwik_Tracker::getDatabase()->query( 
    210                                         "INSERT INTO " . Piwik_Common::prefixTable('log_conversion') . "        ($fields)  
    211                                         VALUES ($bindFields) ", array_values($newGoal)  
     210                                        "INSERT INTO " . Piwik_Common::prefixTable('log_conversion') . "        ($fields) 
     211                                        VALUES ($bindFields) ", array_values($newGoal) 
    212212                                ); 
    213213                        } catch( Exception $e) { 
    214214                                if(Piwik_Tracker::isErrNo($e, '1062')) 
  • core/Tracker/Visit.php

     
    9595 
    9696                $goalManager = new Piwik_Tracker_GoalManager(); 
    9797                $someGoalsConverted = false; 
    98                 $actionId = 0; 
     98                $actionUrlId = 0; 
    9999                $action = null; 
    100100 
    101101                $idGoal = Piwik_Common::getRequestVar('idgoal', 0, 'int', $this->request); 
     
    116116                        $action = $this->newAction(); 
    117117                        $this->handleAction($action); 
    118118                        $someGoalsConverted = $goalManager->detectGoalsMatchingUrl($this->idsite, $action); 
    119                         $actionId = $action->getIdAction(); 
     119 
     120                        $action->loadIdActionNameAndUrl(); 
     121                        $actionUrlId = $action->getIdActionUrl(); 
    120122                } 
    121123 
    122124                // the visitor and session 
     
    133135                if( $this->isVisitorKnown() 
    134136                        && $isLastActionInTheSameVisit) 
    135137                { 
    136                         $idActionReferer = $this->visitorInfo['visit_exit_idaction']; 
     138                        $idActionReferer = $this->visitorInfo['visit_exit_idaction_url']; 
    137139                        try { 
    138                                 $this->handleKnownVisit($actionId, $someGoalsConverted); 
     140                                $this->handleKnownVisit($actionUrlId, $someGoalsConverted); 
    139141                                if(!is_null($action)) 
    140142                                { 
    141143                                        $action->record(        $this->visitorInfo['idvisit'], 
     
    156158                if(!$this->isVisitorKnown() 
    157159                        || !$isLastActionInTheSameVisit) 
    158160                { 
    159                         $this->handleNewVisit($actionId, $someGoalsConverted); 
     161                        $this->handleNewVisit($actionUrlId, $someGoalsConverted); 
    160162                                if(!is_null($action)) 
    161163                        { 
    162164                                $action->record( $this->visitorInfo['idvisit'], 0, 0 ); 
     
    211213         * 
    212214         * 2) Update the visit information 
    213215         */ 
    214         protected function handleKnownVisit($actionId, $someGoalsConverted) 
     216        protected function handleKnownVisit($actionUrlId, $someGoalsConverted) 
    215217        { 
    216218                $serverTime     = $this->getCurrentTimestamp(); 
    217219                $datetimeServer = Piwik_Tracker::getDatetimeFromTimestamp($serverTime); 
     
    224226                } 
    225227 
    226228                $sqlActionIdUpdate = ''; 
    227                 if(!empty($actionId)) 
     229                if(!empty($actionUrlId)) 
    228230                { 
    229                         $sqlActionIdUpdate = "visit_exit_idaction = ". $actionId .", 
     231                        $sqlActionIdUpdate = "visit_exit_idaction_url = ". $actionUrlId .", 
    230232                                                                        visit_total_actions = visit_total_actions + 1, "; 
    231                         $this->visitorInfo['visit_exit_idaction'] = $actionId; 
     233                        $this->visitorInfo['visit_exit_idaction_url'] = $actionUrlId; 
    232234                } 
    233  
    234                 $result = Piwik_Tracker::getDatabase()->query("/* SHARDING_ID_SITE = ". $this->idsite ." */ 
     235                $statement = Piwik_Tracker::getDatabase()->query("/* SHARDING_ID_SITE = ". $this->idsite ." */ 
    235236                                                        UPDATE ". Piwik_Common::prefixTable('log_visit')." 
    236237                                                        SET $sqlActionIdUpdate 
    237238                                                                $sqlUpdateGoalConverted 
     
    244245                                                                        $this->visitorInfo['idvisit'], 
    245246                                                                        $this->visitorInfo['visitor_idcookie'] ) 
    246247                                ); 
    247  
    248                 if(Piwik_Tracker::getDatabase()->rowCount($result) == 0) 
     248                if($statement->rowCount() == 0) 
    249249                { 
    250250                        throw new Piwik_Tracker_Visit_VisitorNotFoundInDatabase("The visitor with visitor_idcookie=".$this->visitorInfo['visitor_idcookie']." and idvisit=".$this->visitorInfo['idvisit']." wasn't found in the DB, we fallback to a new visitor"); 
    251251                } 
     
    267267         * 
    268268         * 2) Insert the visit information 
    269269         */ 
    270         protected function handleNewVisit($actionId, $someGoalsConverted) 
     270        protected function handleNewVisit($actionUrlId, $someGoalsConverted) 
    271271        { 
    272272                printDebug("New Visit."); 
    273273 
     
    297297                        'visit_first_action_time' => Piwik_Tracker::getDatetimeFromTimestamp($serverTime), 
    298298                        'visit_last_action_time' =>  Piwik_Tracker::getDatetimeFromTimestamp($serverTime), 
    299299                        'visit_server_date'     => $serverDate, 
    300                         'visit_entry_idaction'  => $actionId, 
    301                         'visit_exit_idaction'   => $actionId, 
     300                        'visit_entry_idaction_url' => $actionUrlId, 
     301                        'visit_exit_idaction_url' => $actionUrlId, 
    302302                        'visit_total_actions'   => 1, 
    303303                        'visit_total_time'              => $defaultTimeOnePageVisit, 
    304304                        'visit_goal_converted'  => $someGoalsConverted ? 1: 0, 
     
    531531                                $this->visitorInfo['visit_last_action_time'] = $timestampLastAction; 
    532532                                $this->visitorInfo['visit_first_action_time'] = $timestampFirstAction; 
    533533                                $this->visitorInfo['idvisit'] = $idVisit; 
    534                                 $this->visitorInfo['visit_exit_idaction'] = $idLastAction; 
     534                                $this->visitorInfo['visit_exit_idaction_url'] = $idLastAction; 
    535535 
    536536                                $this->visitorKnown = true; 
    537537 
     
    569569                                $this->visitorInfo['visit_last_action_time'] = $visitRow['visit_last_action_time']; 
    570570                                $this->visitorInfo['visit_first_action_time'] = $visitRow['visit_first_action_time']; 
    571571                                $this->visitorInfo['idvisit'] = $visitRow['idvisit']; 
    572                                 $this->visitorInfo['visit_exit_idaction'] = $visitRow['visit_exit_idaction']; 
     572                                $this->visitorInfo['visit_exit_idaction_url'] = $visitRow['visit_exit_idaction_url']; 
    573573 
    574574                                $this->visitorKnown = true; 
    575575 
     
    719719                                                                $this->visitorInfo['idvisit'] ); 
    720720 
    721721                // the last action ID is the current exit idaction 
    722                 if(isset($this->visitorInfo['visit_exit_idaction'] )) 
     722                if(isset($this->visitorInfo['visit_exit_idaction_url'] )) 
    723723                { 
    724724                        $this->cookie->set(     Piwik_Tracker::COOKIE_INDEX_ID_LAST_ACTION, 
    725                                                                 $this->visitorInfo['visit_exit_idaction'] ); 
     725                                                                $this->visitorInfo['visit_exit_idaction_url'] ); 
    726726                } 
    727727 
    728728                // for a new visit, we flag the visit with visitor_returning 
  • core/Updates/0.5-rc1.php

     
     1<?php 
     2 
     3Piwik_Query('ALTER TABLE ' . Piwik::prefixTable('log_action'). ' ADD COLUMN `hash` INTEGER(10) UNSIGNED NOT NULL AFTER `name`;'); 
     4Piwik_Query('UPDATE '.  Piwik::prefixTable('log_action'). ' SET `hash` = CRC32(name);'); 
     5Piwik_Query('CREATE INDEX index_type_hash ON '. Piwik::prefixTable('log_action') .' (type, hash);'); 
     6Piwik_Query('DROP INDEX index_type_name ON '. Piwik::prefixTable('log_action') .';'); 
     7 
     8Piwik_Query('ALTER TABLE '. Piwik::prefixTable('log_visit') .' CHANGE visit_exit_idaction visit_exit_idaction_url INTEGER(11) NOT NULL;'); 
     9Piwik_Query('ALTER TABLE '. Piwik::prefixTable('log_visit') .' CHANGE visit_entry_idaction visit_entry_idaction_url INTEGER(11) NOT NULL;'); 
     10 
     11Piwik_Query('ALTER TABLE ' . Piwik::prefixTable('log_link_visit_action'). ' CHANGE `idaction_ref` `idaction_url_ref` INTEGER(10) UNSIGNED NOT NULL;'); 
     12Piwik_Query('ALTER TABLE ' . Piwik::prefixTable('log_link_visit_action'). ' CHANGE `idaction` `idaction_url` INTEGER(10) UNSIGNED NOT NULL;'); 
     13Piwik_Query('ALTER TABLE ' . Piwik::prefixTable('log_link_visit_action'). ' ADD COLUMN `idaction_name` INTEGER(10) UNSIGNED AFTER `idaction_url_ref`;'); 
  • core/Piwik.php

     
    609609                        'log_action' => "CREATE TABLE {$prefixTables}log_action ( 
    610610                                                                          idaction INTEGER(10) UNSIGNED NOT NULL AUTO_INCREMENT, 
    611611                                                                          name VARCHAR(255) NOT NULL, 
     612                                                                          hash INTEGER(10) UNSIGNED NOT NULL, 
    612613                                                                          type TINYINT UNSIGNED NULL, 
    613614                                                                          PRIMARY KEY(idaction), 
    614                                                                           INDEX index_type_name (type, name(15)) 
     615                                                                          INDEX index_type_hash (type, hash) 
    615616                                                )  DEFAULT CHARSET=utf8  
    616617                        ", 
    617618                                         
     
    624625                                                          visit_first_action_time DATETIME NOT NULL, 
    625626                                                          visit_last_action_time DATETIME NOT NULL, 
    626627                                                          visit_server_date DATE NOT NULL, 
    627                                                           visit_exit_idaction INTEGER(11) NOT NULL, 
    628                                                           visit_entry_idaction INTEGER(11) NOT NULL, 
     628                                                          visit_exit_idaction_url INTEGER(11) NOT NULL, 
     629                                                          visit_entry_idaction_url INTEGER(11) NOT NULL, 
    629630                                                          visit_total_actions SMALLINT(5) UNSIGNED NOT NULL, 
    630631                                                          visit_total_time SMALLINT(5) UNSIGNED NOT NULL, 
    631632                                                          visit_goal_converted TINYINT(1) NOT NULL, 
     
    684685                        'log_link_visit_action' => "CREATE TABLE {$prefixTables}log_link_visit_action ( 
    685686                                                                                          idlink_va INTEGER(11) NOT NULL AUTO_INCREMENT, 
    686687                                                                                          idvisit INTEGER(10) UNSIGNED NOT NULL, 
    687                                                                                           idaction INTEGER(10) UNSIGNED NOT NULL, 
    688                                                                                           idaction_ref INTEGER(11) UNSIGNED NOT NULL, 
     688                                                                                          idaction_url INTEGER(10) UNSIGNED NOT NULL, 
     689                                                                                          idaction_url_ref INTEGER(10) UNSIGNED NOT NULL, 
     690                                                                                          idaction_name INTEGER(10) UNSIGNED, 
    689691                                                                                          time_spent_ref_action INTEGER(10) UNSIGNED NOT NULL, 
    690692                                                                                          PRIMARY KEY(idlink_va), 
    691693                                                                                          INDEX index_idvisit(idvisit) 
  • core/ArchiveProcessing/Day.php

     
    2828                $this->db = Zend_Registry::get('db'); 
    2929                $this->debugAlwaysArchive = Zend_Registry::get('config')->Debug->always_archive_data_day; 
    3030        } 
    31          
     31 
    3232        /** 
    3333         * Main method to process logs for a day. The only logic done here is computing the number of visits, actions, etc. 
    3434         * All the other reports are computed inside plugins listening to the event 'ArchiveProcessing_Day.compute'. 
  • tests/core/Tracker/Action.test.php

     
    2323                        // outlinks 
    2424                        array( 
    2525                                'request' => array( 'link' => 'http://example.org'), 
    26                                 'expected' => array(    'name' => 'http://example.org', 
     26                                'expected' => array(    'name' => null, 
    2727                                                                                'url' => 'http://example.org', 
    2828                                                                                'type' => Piwik_Tracker_Action::TYPE_OUTLINK), 
    2929                        ), 
     30                        // outlinks with custom name 
     31                        array( 
     32                                'request' => array( 'link' => 'http://example.org', 'action_name' => 'Example.org'), 
     33                                'expected' => array(    'name' => 'Example.org', 
     34                                                                                'url' => 'http://example.org', 
     35                                                                                'type' => Piwik_Tracker_Action::TYPE_OUTLINK), 
     36                        ), 
    3037                        // keep the case in urls, but trim 
    3138                        array( 
    3239                                'request' => array( 'link' => ' http://example.org/Category/Test/       '), 
    33                                 'expected' => array(    'name' => 'http://example.org/Category/Test/', 
     40                                'expected' => array(    'name' => null, 
    3441                                                                                'url' => 'http://example.org/Category/Test/', 
    3542                                                                                'type' => Piwik_Tracker_Action::TYPE_OUTLINK), 
    3643                        ), 
    37                          
     44 
     45                        // trim the custom name 
     46                        array( 
     47                                'request' => array( 'link' => ' http://example.org/Category/Test/       ', 'action_name' => '  Example dot org '), 
     48                                'expected' => array(    'name' => 'Example dot org', 
     49                                                                                'url' => 'http://example.org/Category/Test/', 
     50                                                                                'type' => Piwik_Tracker_Action::TYPE_OUTLINK), 
     51                        ), 
     52 
    3853                        // downloads 
    3954                        array( 
    4055                                'request' => array( 'download' => 'http://example.org/*$test.zip'), 
    41                                 'expected' => array(    'name' => 'http://example.org/*$test.zip', 
     56                                'expected' => array(    'name' => null, 
    4257                                                                                'url' => 'http://example.org/*$test.zip', 
    4358                                                                                'type' => Piwik_Tracker_Action::TYPE_DOWNLOAD), 
    4459                        ), 
     60 
     61                        // downloads with custom name 
     62                        array( 
     63                                'request' => array( 'download' => 'http://example.org/*$test.zip', 'action_name' => 'Download test.zip'), 
     64                                'expected' => array(    'name' => 'Download test.zip', 
     65                                                                                'url' => 'http://example.org/*$test.zip', 
     66                                                                                'type' => Piwik_Tracker_Action::TYPE_DOWNLOAD), 
     67                        ), 
     68                         
    4569                        // keep the case and multiple / in urls 
    4670                        array( 
    4771                                'request' => array( 'download' => 'http://example.org/CATEGORY/test///test.pdf'), 
    48                                 'expected' => array(    'name' => 'http://example.org/CATEGORY/test///test.pdf', 
     72                                'expected' => array(    'name' => null, 
    4973                                                                                'url' => 'http://example.org/CATEGORY/test///test.pdf', 
    5074                                                                                'type' => Piwik_Tracker_Action::TYPE_DOWNLOAD), 
    5175                        ), 
     
    5377                        // page view 
    5478                        array( 
    5579                                'request' => array( 'url' => 'http://example.org/'), 
    56                                 'expected' => array(    'name' => 'index', 
     80                                'expected' => array(    'name' => null, 
    5781                                                                                'url' => 'http://example.org/', 
    5882                                                                                'type' => Piwik_Tracker_Action::TYPE_ACTION), 
    5983                        ), 
    6084                        array( 
     85                                'request' => array( 'url' => 'http://example.org/', 'action_name' => 'Example.org Website'), 
     86                                'expected' => array(    'name' => 'Example.org Website', 
     87                                                                                'url' => 'http://example.org/', 
     88                                                                                'type' => Piwik_Tracker_Action::TYPE_ACTION), 
     89                        ), 
     90                        array( 
    6191                                'request' => array( 'url' => 'http://example.org/CATEGORY/'), 
    62                                 'expected' => array(    'name' => 'CATEGORY/index', 
     92                                'expected' => array(    'name' => null, 
    6393                                                                                'url' => 'http://example.org/CATEGORY/', 
    6494                                                                                'type' => Piwik_Tracker_Action::TYPE_ACTION), 
    6595                        ), 
    6696                        array( 
     97                                'request' => array( 'url' => 'http://example.org/CATEGORY/TEST', 'action_name' => 'Example.org / Category / test /'), 
     98                                'expected' => array(    'name' => 'Example.org/Category/test', 
     99                                                                                'url' => 'http://example.org/CATEGORY/TEST', 
     100                                                                                'type' => Piwik_Tracker_Action::TYPE_ACTION), 
     101                        ), 
     102 
     103                        // empty request 
     104                        array( 
     105                                'request' => array(), 
     106                                'expected' => array(    'name' => null, 'url' => '/', 
     107                                                                                'type' => Piwik_Tracker_Action::TYPE_ACTION), 
     108                        ), 
     109                        array( 
    67110                                'request' => array( 'url' => 'http://example.org/category/', 
    68111                                                                        'action_name' => 'custom name with/one delimiter/two delimiters/'), 
    69112                                'expected' => array(    'name' => 'custom name with/one delimiter/two delimiters', 
     
    80123                        // testing: delete tab, trimmed, not strtolowered 
    81124                        array(  
    82125                                'request' => array( 'url' => "http://example.org/category/test///test  wOw      "), 
    83                                 'expected' => array(    'name' => 'category/test/test  wOw', 
     126                                'expected' => array(    'name' => null, 
    84127                                                                                'url' => 'http://example.org/category/test///test  wOw', 
    85128                                                                                'type' => Piwik_Tracker_Action::TYPE_ACTION), 
    86129                        ), 
    87130                        // testing: inclusion of zero values in action name 
    88131                        array( 
    89132                                'request' => array( 'url' => "http://example.org/category/1/0/t/test"), 
    90                                 'expected' => array(    'name' => 'category/1/0/t/test', 
     133                                'expected' => array(    'name' => null, 
    91134                                                                                'url' => 'http://example.org/category/1/0/t/test', 
    92135                                                                                'type' => Piwik_Tracker_Action::TYPE_ACTION), 
    93136                        ), 
  • tests/core/Config.test.php

     
    1515        $globalFile = PIWIK_INCLUDE_PATH . '/tests/resources/Config/global.ini.php'; 
    1616         
    1717        $config = new Piwik_Config($userFile, $globalFile); 
     18                Zend_Registry::set('config', $config); 
     19 
    1820        $config->init(); 
     21 
    1922        $this->assertEqual($config->Category->key1, "value_overwritten"); 
    2023        $this->assertEqual($config->Category->key2, "value2"); 
    2124        $this->assertEqual($config->General->login, 'tes"t'); 
  • tests/resources/plugins/Actions/Actions.config.ini.php

     
     1[General] 
     2action_category_delimiter = / 
     3 
     4[Tracker] 
     5default_action_name = index 
  • tests/resources/Tracker/Action.config.ini.php

     
    11[Tracker] 
    22action_category_delimiter = / 
     3default_action_name             = index 
     4default_action_url              = / 
     5 No newline at end of file 
  • config/global.ini.php

     
    134134; this action name is used when the javascript variable piwik_action_name is not specified in the piwik javascript code, and when the URL has no path. 
    135135default_action_name             = index 
    136136 
     137; this action url is used when URL was not passed to Piwik (i.e. when javascript is disabled in browser and referer was not set in the request) 
     138default_action_url              = / 
     139 
    137140; length of a visit in seconds. If a visitor comes back on the website visit_standard_length seconds after his last page view, it will be recorded as a new visit   
    138141visit_standard_length       = 1800 
    139142