Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

adding proper google analytics plugin version

  • Loading branch information...
commit 3ee7e55503fe4922274825025ee05fb3439df8e9 1 parent 5b7b02f
@bshaffer authored
Showing with 4,148 additions and 677 deletions.
  1. +229 −146 plugins/sfGoogleAnalyticsPlugin/README
  2. +32 −17 plugins/sfGoogleAnalyticsPlugin/config/app.yml
  3. +28 −6 plugins/sfGoogleAnalyticsPlugin/config/config.php
  4. +9 −0 plugins/sfGoogleAnalyticsPlugin/config/module.yml
  5. +0 −67 plugins/sfGoogleAnalyticsPlugin/lib/action/sfGoogleAnalyticsActionMixin.class.php
  6. +0 −13 plugins/sfGoogleAnalyticsPlugin/lib/exception/sfGoogleAnalyticsException.class.php
  7. +53 −100 plugins/sfGoogleAnalyticsPlugin/lib/filter/sfGoogleAnalyticsFilter.class.php
  8. +167 −32 plugins/sfGoogleAnalyticsPlugin/lib/helper/GoogleAnalyticsHelper.php
  9. +36 −0 plugins/sfGoogleAnalyticsPlugin/lib/listener/sfGoogleAnalyticsListener.class.php
  10. +36 −0 plugins/sfGoogleAnalyticsPlugin/lib/mixin/sfGoogleAnalyticsMixin.class.php
  11. +945 −0 plugins/sfGoogleAnalyticsPlugin/lib/tracker/sfGoogleAnalyticsTracker.class.php
  12. +242 −0 plugins/sfGoogleAnalyticsPlugin/lib/tracker/sfGoogleAnalyticsTrackerGoogle.class.php
  13. +205 −0 plugins/sfGoogleAnalyticsPlugin/lib/tracker/sfGoogleAnalyticsTrackerUrchin.class.php
  14. +95 −0 plugins/sfGoogleAnalyticsPlugin/lib/transaction/sfGoogleAnalyticsItem.class.php
  15. +130 −0 plugins/sfGoogleAnalyticsPlugin/lib/transaction/sfGoogleAnalyticsTransaction.class.php
  16. +0 −50 plugins/sfGoogleAnalyticsPlugin/lib/user/sfGoogleAnalyticsUserMixin.class.php
  17. +11 −224 plugins/sfGoogleAnalyticsPlugin/lib/util/sfGoogleAnalyticsToolkit.class.php
  18. +27 −22 plugins/sfGoogleAnalyticsPlugin/package.xml
  19. +37 −0 plugins/sfGoogleAnalyticsPlugin/test/bootstrap/functional.php
  20. +21 −0 plugins/sfGoogleAnalyticsPlugin/test/bootstrap/unit.php
  21. +2 −0  plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/apps/frontend/config/app.yml
  22. +4 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/apps/frontend/config/cache.yml
  23. +8 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/apps/frontend/config/config.php
  24. +35 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/apps/frontend/config/factories.yml
  25. +10 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/apps/frontend/config/filters.yml
  26. +7 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/apps/frontend/config/i18n.yml
  27. +22 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/apps/frontend/config/logging.yml
  28. +15 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/apps/frontend/config/routing.yml
  29. +2 −0  plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/apps/frontend/config/security.yml
  30. +102 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/apps/frontend/config/settings.yml
  31. +17 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/apps/frontend/config/view.yml
  32. +5 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/apps/frontend/lib/myUser.class.php
  33. +21 −0 ...ogleAnalyticsPlugin/test/functional/fixtures/symfony10/apps/frontend/modules/main/actions/actions.class.php
  34. 0  ...gleAnalyticsPlugin/test/functional/fixtures/symfony10/apps/frontend/modules/main/templates/indexSuccess.php
  35. +18 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/apps/frontend/templates/layout.php
  36. +5 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/config/config.php
  37. +5 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/config/databases.yml
  38. +44 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/config/propel.ini
  39. +2 −0  plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/config/properties.ini
  40. +4 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/config/rsync_exclude.txt
  41. 0  plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/config/schema.yml
  42. +14 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/symfony
  43. +29 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/test/bootstrap/functional.php
  44. +17 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/test/bootstrap/unit.php
  45. +15 −0 ...ins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/test/functional/frontend/mainActionsTest.php
  46. +26 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/web/.htaccess
  47. +27 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/web/css/main.css
  48. +10 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/web/frontend_dev.php
  49. +10 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/web/index.php
  50. +2 −0  plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony10/web/robots.txt
  51. +2 −0  plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/apps/frontend/config/app.yml
  52. +4 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/apps/frontend/config/cache.yml
  53. +115 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/apps/frontend/config/factories.yml
  54. +8 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/apps/frontend/config/filters.yml
  55. +8 −0 ...ogleAnalyticsPlugin/test/functional/fixtures/symfony11/apps/frontend/config/frontendConfiguration.class.php
  56. +15 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/apps/frontend/config/routing.yml
  57. +2 −0  plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/apps/frontend/config/security.yml
  58. +104 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/apps/frontend/config/settings.yml
  59. +17 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/apps/frontend/config/view.yml
  60. +5 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/apps/frontend/lib/myUser.class.php
  61. +22 −0 ...ogleAnalyticsPlugin/test/functional/fixtures/symfony11/apps/frontend/modules/main/actions/actions.class.php
  62. 0  ...gleAnalyticsPlugin/test/functional/fixtures/symfony11/apps/frontend/modules/main/templates/indexSuccess.php
  63. +18 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/apps/frontend/templates/layout.php
  64. 0  ...ns/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/cache/frontend/test/config/config_app.yml.php
  65. +24 −0 ...nalyticsPlugin/test/functional/fixtures/symfony11/cache/frontend/test/config/config_config_handlers.yml.php
  66. +54 −0 ...GoogleAnalyticsPlugin/test/functional/fixtures/symfony11/cache/frontend/test/config/config_settings.yml.php
  67. +11 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/config/ProjectConfiguration.class.php
  68. +5 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/config/databases.yml
  69. +49 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/config/propel.ini
  70. +2 −0  plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/config/properties.ini
  71. +5 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/config/rsync_exclude.txt
  72. 0  plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/config/schema.yml
  73. +15 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/symfony
  74. +26 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/test/bootstrap/functional.php
  75. +15 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/test/bootstrap/unit.php
  76. +13 −0 ...ins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/test/functional/frontend/mainActionsTest.php
  77. +22 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/web/.htaccess
  78. 0  plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/web/css/main.css
  79. +12 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/web/frontend_dev.php
  80. +6 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/web/index.php
  81. +2 −0  plugins/sfGoogleAnalyticsPlugin/test/functional/fixtures/symfony11/web/robots.txt
  82. +106 −0 plugins/sfGoogleAnalyticsPlugin/test/functional/frontend/mainActionsTest.php
  83. +79 −0 plugins/sfGoogleAnalyticsPlugin/test/unit/GoogleAnalyticsHelperTest.php
  84. +9 −0 plugins/sfGoogleAnalyticsPlugin/test/unit/sfGoogleAnalyticsFilterTest.php
  85. +29 −0 plugins/sfGoogleAnalyticsPlugin/test/unit/sfGoogleAnalyticsItemTest.php
  86. +8 −0 plugins/sfGoogleAnalyticsPlugin/test/unit/sfGoogleAnalyticsMixinTest.php
  87. +70 −0 plugins/sfGoogleAnalyticsPlugin/test/unit/sfGoogleAnalyticsTrackerGoogleTest.php
  88. +356 −0 plugins/sfGoogleAnalyticsPlugin/test/unit/sfGoogleAnalyticsTrackerTest.php
  89. +74 −0 plugins/sfGoogleAnalyticsPlugin/test/unit/sfGoogleAnalyticsTrackerUrchinTest.php
  90. +41 −0 plugins/sfGoogleAnalyticsPlugin/test/unit/sfGoogleAnalyticsTransactionTest.php
  91. +14 −0 symfony
View
375 plugins/sfGoogleAnalyticsPlugin/README
@@ -1,168 +1,250 @@
= sfGoogleAnalyticsPlugin plugin =
-Easily adds tracking code for [http://www.google.com/analytics Google Analytics] to your presentation layer.
+Easily add [http://www.google.com/analytics Google Analytics] tracking code to your presentation layer.
-== Features ==
-
- * `sfGoogleAnalyticsActionMixin`: Adds convenience methods to your actions.
- * `sfGoogleAnalyticsFilter`: Adds necessary tracking code to the bottom of every HTML page.
- * `GoogleAnalyticsHelper`: Helper functions for adding `urchinTracker` calls to links.
+''This documentation is a work in progress. Thank you for your patience.''
== Installation ==
- * Install the plugin:
-
- {{{
- ./symfony plugin-install http://plugins.symfony-project.com/sfGoogleAnalyticsPlugin
- }}}
-
- If you use Subversion to install your plugins, please connect to the 1.0 branch at the following URL. Development for [#Version1.1Roadmap version 1.1] of this plugin has begun in the trunk, which is now unstable.
-
- {{{
- http://svn.symfony-project.com/plugins/sfGoogleAnalyticsPlugin/branches/1.0
- }}}
-
- * Configure your Google Analytics account in `app.yml`:
-
- {{{
- prod:
- google_analytics:
- enabled: on
- uacct: xx-xxxxxxx-x # <-- put your site's account number here
-
- all:
- google_analytics:
- enabled: off
- }}}
-
- * Add `sfGoogleAnalyticsFilter` to `filters.yml` just after `web_debug`:
-
- {{{
- rendering: ~
- web_debug: ~
- google_analytics:
- class: sfGoogleAnalyticsFilter
- # etc...
- }}}
-
-== Usage ==
-
-Just by adding the filter and enabling the plugin in `app.yml` your site should begin tracking on your Google Analytics account. Beyond this, there are a few more pieces of functionality that allow you finer control over how your site interacts with Google Analytics.
-
-=== Track a page as a custom URI ===
-
- {{{
- // from inside an action
- null $this->setGoogleAnalyticsParam(string $utParam)
- }}}
-
-If any of your actions call any of the `forward` methods, the action that actually renders will likely not be the action referenced in the browser's address bar. This mixed-in method allows you to specify a URI to send up to Google Analytics once the page is loaded other that what is in the address bar.
-
-For example, if you want to track how many visitors land on your `error_404_action`, you could call this:
-
- {{{
- // from inside an action
- $this->setGoogleAnalyticsParam('/error/404?page='.$this->getModuleName().'/'.$this->getActionName());
- }}}
-
-=== Set a custom initialization variable ===
-
- {{{
- // from inside an action
- null $this->addGoogleAnalyticsVar(string $name, string $value)
- }}}
-
-You can add a custom variable to the Javascript code that initializes Google Analytics using this method. For example, if you want to track an action as a different subdomain:
-
- {{{
- // from inside an action
- $this->addGoogleAnalyticsVar('udn', 'domain.com');
- }}}
-
-This call will add a `_udn` variable to your initialization block:
-
- {{{
- <script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
- </script>
- <script type="text/javascript">
- _uacct="xx-xxxxxxx-x";
- _udn="domain.com";
- urchinTracker();
- </script>
- }}}
-
-=== Track clicks on a link ===
-
- {{{
- string google_analytics_link_to(string $name, string $internalUri[, string $urchinUri[, array $options]])
- }}}
-
-You'll want to use this helper to track outbound links as well as those that go to a local file that doesn't have Google Analytics tracking code at the bottom (e.g. a PDF or image).
-
-For example, if you want to track a link to the symfony site:
-
- {{{
- <?php use_helper('GoogleAnalytics') ?>
-
- <p>
- For more information, please visit the
- <?php echo google_analytics_link_to('symfony project site',
- 'http://www.symfony-project.com',
- '/outbound/symfony') ?>.
- </p>
- }}}
-
-Or to track downloads of a PDF:
-
- {{{
- <?php use_helper('GoogleAnalytics') ?>
-
- <p>
- You can also download <?php echo google_analytics_link_to('the PDF version',
- '/doc/the-book.pdf') ?>.
- </p>
- }}}
+=== 1. Install ===
-=== Track clicks on a Javascript link ===
+You can install using the `plugin-install` task:
- {{{
- string google_analytics_link_to_function(string $name, string $function, string $urchinUri[, array $options])
- }}}
+{{{
+php symfony plugin-install sfGoogleAnalyticsPlugin
+}}}
-This helper function will send a call to Google Analytics when your user clicks a Javascript link. For example, if you want to track calls to a link that closes a popup window:
+You can also pull the code directly from the [http://svn.symfony-project.org/plugins/sfGoogleAnalyticsPlugin/trunk Subversion repository] using a `svn checkout` or the `svn:externals` property on your project's `/plugins` directory.
- {{{
- <?php use_helper('GoogleAnalytics') ?>
-
- <p><?php echo google_analytics_link_to_function('close window',
- 'window.close()',
- '/popups/mom/close',
- 'id=closer') ?></p>
- }}}
+Once the plugin code is accessible to your project, you need to add the `sfGoogleAnalyticsFilter` to your filter chain:
-=== Specify where tracking code should be inserted ===
+{{{
+#!yaml
+rendering: ~
+security: ~
-By changing the `insertion` configuration variable, you can specify where in the response content the tracking code should be placed. The plugin comes with two options pre-built, `top` and `bottom`.
+# insert your own filters here
+sf_google_analytics_plugin:
+ class: sfGoogleAnalyticsFilter
- {{{
- prod:
- google_analytics:
- enabled: on
-
- all:
- google_analytics:
- uacct: xx-xxxxxxx-x
- insertion: top
- }}}
+cache: ~
+common: ~
+execution: ~
+}}}
+
+''NOTE: This is the symfony 1.1 `filters.yml` file. The equivalent symfony 1.0 file looks slightly different.''
+
+=== 2. Configure ===
+
+Basic configuration is done in your application's `app.yml` file:
+
+{{{
+#!yaml
+all:
+ sf_google_analytics_plugin:
+ enabled: on
+ profile_id: XX-XXXXX-X
+ tracker: google
+}}}
+
+You'll have to copy the `profile_id` value out of the tracking code Google supplies for your site profile. This value typically starts with the letter U and ends with a single digit.
+
+This plugin defaults to using the older `urchin` tracker. To take advantage of the latest featureset of Google Analytics, change the `tracker` value to `google`. This will insert the new `ga.js` tracking code into your project.
+
+== Advanced Usage ==
+
+This plugin provides much more functionality than a simple insert of your tracking code. Here are some highlights:
+
+=== How do I customize the name a page is tracked as? ===
+
+If you would like to track a certain page as something other than what appears in the browser address bar, you can do so by modifying the `page_name` parameter in `module.yml`:
+
+{{{
+#!yaml
+all:
+ myAction:
+ sf_google_analytics_plugin:
+ params:
+ page_name: something_else
+}}}
+
+For finer control over when the alternate page name is used, you can access the tracker object directly in your action. This also exposes additional funcionality.
+
+==== Option: `use_flash` ====
+
+For example, if you want to track a successful form submission for a form that redirects to the same page on success and on error:
+
+{{{
+#!php
+<?php
+
+class mainActions extends sfActions
+{
+ public function executeContact()
+ {
+ // form submission logic...
-These settings will place the tracking code just inside the response's opening `<body>` tag (in the `prod` environment). The plugin defaults to placing the tracking code just before the response's closing `</body>` tag.
+ if ($success)
+ {
+ $this->getTracker()->setPageName('/contact/success', array(
+ 'use_flash' => true,
+ ));
-== Version 1.1 Roadmap ==
+ $this->setFlash('feedback', 'Thank you!');
-Refactor plugin to accommodate both version of Google Analytics tracking code: legacy Urchin Javascript and the new Google Javascript.
+ $this->redirect('main/contact');
+ }
+ }
+}
+}}}
+
+In this example, the request after the successful form post will be tracked as `/contact/success`.
+
+==== Option: `is_route` ====
+
+One more option available is the `is_route` option. When this flag is applied, the string provided for a page name will be passed through `sfRouting` before being added to the page. Using this option allows you to centralize all URLs, those real and for tracking purposes only, in your application's `routing.yml` file:
+
+{{{
+#!yaml
+contact:
+ url: /contact
+ param: { module: main, action: contact }
+
+# be sure the tracking rule comes AFTER the real rule so the application
+# doesn't use it for any url_for('main/contact') calls
+track_contact:
+ url: /contact/success
+ param: { module: main, action: contact }
+}}}
+
+{{{
+#!php
+<?php
+
+class mainActions extends sfActions
+{
+ public function executeContact()
+ {
+ // form submission logic...
+
+ if ($success)
+ {
+ $this->getTracker()->setPageName('@track_contact', array(
+ 'use_flash' => true,
+ 'is_route' => true,
+ ));
+
+ $this->setFlash('feedback', 'Thank you!');
+
+ $this->redirect('@contact');
+ }
+ }
+}
+}}}
+
+=== How do I selectively disable tracking? ===
+
+You can easily configure the tracking code for a single module or even a single action by using the `module.yml` configuration file:
+
+{{{
+#!yaml
+all:
+ # disable tracking for this module...
+ sf_google_analytics_plugin:
+ params:
+ enabled off
+
+ # ...or for a single action
+ index:
+ sf_google_analytics_plugin:
+ params:
+ enabled off
+}}}
+
+Alternatively, you can access the tracker object directly from inside your action:
+
+{{{
+#!php
+<?php
+
+class mainActions extends sfActions
+{
+ public function executeIndex()
+ {
+ $this->getTracker()->setEnabled(false);
+ }
+}
+}}}
+
+=== Can I insert the tracking code at the top of my page? ===
+
+You can configure this in `app.yml`:
+
+{{{
+#!yaml
+all:
+ sf_google_analytics_plugin:
+ profile_id: XX-XXXXX-X
+ insertion: top
+}}}
+
+=== Can I track demographic information? ===
+
+You can expose whatever information you store on your users (that your privacy policy allows, of course) to Google Analytics. This is best done in your sign-in routine. For example, if you're using [wiki:sfGuardPlugin]:
+
+{{{
+#!php
+<?php
+
+class myUser extends sfGuardSecurityUser
+{
+ /**
+ * Overload to add custom tracking variables to the current user.
+ *
+ * Variables are added using flash, assuming sign in will be followed by a
+ * redirect.
+ *
+ * @see sfGuardSecurityUser
+ */
+ public function signIn($user, $remember = false, $con = null)
+ {
+ parent::signIn($user, $remember, $con);
+
+ // assign tracking variables
+ if ($gender = $user->getProfile()->getGender())
+ {
+ $this->getTracker()->setVar('gender/'.$gender, array(
+ 'use_flash' => true,
+ ));
+ }
+ if ($this->hasCredential('moderator'))
+ {
+ $this->getTracker()->setVar('userType/moderator', array(
+ 'use_flash' => true,
+ ));
+ }
+ }
+}
+}}}
== Changelog ==
+=== Version 1.1.2 ===
+
+ * Fixed symfony 1.1 compatibility in `sfLogger` interactions.
+
+=== Version 1.1.1 ===
+
+ * Fixed Javascript case-sensitivity bug.
+
+=== Version 1.1.0 ===
+
+ * '''Added support for new Google Javascript library (`ga.js`).'''
+ * Updated API to include more human-readable method names.
+ * Added support for tracking e-commerce transactions.
+ * Added option to parse tracking argument with `sfRouting`.
+ * Added option to defer many tracker calls to the next response, similar to `sfFlash` storage (helpful for redirects).
+
=== Version 1.0-RC1 ===
* Renamed plugin from sfUrchinPlugin to sfGoogleAnalyticsPlugin.
@@ -189,3 +271,4 @@ Refactor plugin to accommodate both version of Google Analytics tracking code: l
== Maintainers ==
Kris Wallsmith
+
View
49 plugins/sfGoogleAnalyticsPlugin/config/app.yml
@@ -1,18 +1,33 @@
# all:
-# google_analytics:
-# enabled: off
-# uacct: ~ # Profile number
-# insertion: bottom # Where to insert the tracking code (top or bottom)
-# vars: # Custom init variables - http://www.google.com/support/googleanalytics/bin/answer.py?answer=75129
-# udn: ~ # Set a custom domain name - http://www.google.com/support/googleanalytics/bin/answer.py?answer=75129
-# uccn: ~ # Custom campaign variable - http://www.google.com/support/googleanalytics/bin/answer.py?answer=75768
-# ucsr: ~ # Custom source variable
-# ucmd: ~ # Custom medium variable
-# uctr: ~ # Custom term variable
-# ucct: ~ # Custom content variable
-# ulink: ~ # Linker functionality - http://www.google.com/support/googleanalytics/bin/answer.py?answer=74986
-# utimeout: ~ # Inactive timeout - http://www.google.com/support/googleanalytics/bin/answer.py?answer=74927
-# userv: ~ # Urchin server - http://www.google.com/support/googleanalytics/bin/answer.py?answer=74937
-# custom: [] # For __utmSetVar() - http://www.google.com/support/googleanalytics/bin/answer.py?answer=75010
-# usrc: http://www.google-analytics.com/urchin.js
-# usrc_ssl: https://ssl.google-analytics.com/urchin.js
+# sf_google_analytics_plugin:
+# enabled: off
+# profile_id: XX-XXXXX-X
+# insertion: bottom
+# tracker: urchin
+# classes:
+# urchin: sfGoogleAnalyticsTrackerUrchin
+# google: sfGoogleAnalyticsTrackerGoogle
+#
+# # tracker configuration, all optional
+# params:
+# page_name: ~ # this setting should be used in module.yml, not app.yml
+# domain_name: ~
+# linker_policy: off
+# organic_referers: [{ name: ~, param: ~ }]
+# vars: [] # this setting also makes more sense to use in module.yml, not app.yml
+# cookie_path: /
+# client_info_policy: on
+# hash_policy: on
+# detect_flash_policy: on
+# detect_title_policy: on
+# session_timeout: 3600 # 30 minutes
+# cookie_timeout: 31536000 # six months
+# campaign_keys: { name: ~, source: ~, medium: ~, term: ~, content: ~, id: ~, no_override: ~ }
+# anchor_policy: off
+# ignored_organics: []
+# ignored_referers: []
+# sample_rate: 100 # 100%
+# local_remote_server_policy: off
+#
+# # specific to "google" tracker
+# tracker_var: pageTracker
View
34 plugins/sfGoogleAnalyticsPlugin/config/config.php
@@ -1,8 +1,30 @@
<?php
-sfMixer::register('sfComponent', array('sfGoogleAnalyticsActionMixin', 'setGoogleAnalyticsParam'));
-sfMixer::register('sfComponent', array('sfGoogleAnalyticsActionMixin', 'addGoogleAnalyticsVar'));
-sfMixer::register('sfComponent', array('sfGoogleAnalyticsActionMixin', 'addGoogleAnalyticsCustomVar'));
-sfMixer::register('sfComponent', array('sfGoogleAnalyticsActionMixin', 'addGoogleAnalyticsCustomVarToFlash'));
-
-sfMixer::register('sfUser', array('sfGoogleAnalyticsUserMixin', 'addGoogleAnalyticsCustomVarToFlash'));
+if (defined('SYMFONY_VERSION') && 0 !== strpos(SYMFONY_VERSION, '1.0'))
+{
+ // >= symfony 1.1
+ $listener = array('sfGoogleAnalyticsListener', 'observe');
+
+ $this->dispatcher->connect('request.method_not_found', $listener);
+ $this->dispatcher->connect('response.method_not_found', $listener);
+ $this->dispatcher->connect('component.method_not_found', $listener);
+ $this->dispatcher->connect('user.method_not_found', $listener);
+}
+else
+{
+ // symfony 1.0
+ $getter = array('sfGoogleAnalyticsMixin', 'getTracker');
+ $setter = array('sfGoogleAnalyticsMixin', 'setTracker');
+
+ sfMixer::register('sfRequest', $getter);
+ sfMixer::register('sfRequest', $setter);
+
+ sfMixer::register('sfResponse', $getter);
+ sfMixer::register('sfResponse', $setter);
+
+ sfMixer::register('sfComponent', $getter);
+ sfMixer::register('sfComponent', $setter);
+
+ sfMixer::register('sfUser', $getter);
+ sfMixer::register('sfUser', $setter);
+}
View
9 plugins/sfGoogleAnalyticsPlugin/config/module.yml
@@ -0,0 +1,9 @@
+# all:
+# sf_google_analytics_plugin:
+# # see params section of app.yml
+# params: {}
+#
+# action_name:
+# sf_google_analytics_plugin:
+# # see params section of app.yml
+# params: {}
View
67 plugins/sfGoogleAnalyticsPlugin/lib/action/sfGoogleAnalyticsActionMixin.class.php
@@ -1,67 +0,0 @@
-<?php
-
-/**
- * Action mixin methods for the sfGoogleAnalyticsPlugin.
- *
- * @package sfGoogleAnalyticsPlugin
- * @subpackage action
- * @author Kris Wallsmith <kris.wallsmith@symfony-project.com>
- * @version SVN: $Id: sfGoogleAnalyticsActionMixin.class.php 11928 2008-10-03 16:59:33Z Kris.Wallsmith $
- */
-class sfGoogleAnalyticsActionMixin
-{
- /**
- * Set a custom parameter for Google Analytics initialization.
- *
- * @author Kris Wallsmith
- * @param sfComponent $action
- * @param string $utParam
- */
- public static function setGoogleAnalyticsParam(sfComponent $action, $utParam)
- {
- sfGoogleAnalyticsToolkit::setParam($utParam);
- }
-
- /**
- * Add a Google Analytics initialization variable.
- *
- * @author Kris Wallsmith
- * @param sfComponent $action
- * @param string $name
- * @param string $value
- */
- public static function addGoogleAnalyticsVar(sfComponent $action, $name, $value)
- {
- sfGoogleAnalyticsToolkit::addVar($name, $value);
- }
-
- /**
- * Add a custom variable to Google Analytics.
- *
- * @author Kris Wallsmith
- * @param sfComponent $action
- * @param string $var
- */
- public static function addGoogleAnalyticsCustomVar(sfComponent $action, $var)
- {
- sfGoogleAnalyticsToolkit::addCustomVar($var);
- }
-
- /**
- * Add a custom variable that will render on the next request.
- *
- * @author Kris Wallsmith
- * @param sfComponent $action
- * @param string $var
- * @param bool $persist
- * @see comment block for sfGoogleAnalyticsUserMixin::addGoogleAnalyticsCustomVarToFlash()
- * @todo support updated symfony 1.1 flash architecture
- */
- public static function addGoogleAnalyticsCustomVarToFlash(sfComponent $action, $var, $persist = true)
- {
- $vars = $action->getFlash('google_analytics_custom_vars', array());
- $vars[] = $var;
- $action->setFlash('google_analytics_custom_vars', $vars, $persist);
- }
-
-}
View
13 plugins/sfGoogleAnalyticsPlugin/lib/exception/sfGoogleAnalyticsException.class.php
@@ -1,13 +0,0 @@
-<?php
-
-/**
- * Exception class for sfGoogleAnalyticsPlugin.
- *
- * @package sfGoogleAnalyticsPlugin
- * @subpackage exception
- * @author Kris Wallsmith <kris.wallsmith@symfony-project.com>
- * @version SVN: $Id: sfGoogleAnalyticsException.class.php 11928 2008-10-03 16:59:33Z Kris.Wallsmith $
- */
-class sfGoogleAnalyticsException extends sfException
-{
-}
View
153 plugins/sfGoogleAnalyticsPlugin/lib/filter/sfGoogleAnalyticsFilter.class.php
@@ -1,94 +1,100 @@
<?php
/**
- * Renders tracking code on every page.
- *
- * To activate, add the following code to your application's filters.yml file,
- * just below the web_debug filter.
- *
- * <code>
- * rendering: ~
- * web_debug: ~
- *
- * # sfGoogleAnalyticsPlugin filter
- * google_analytics:
- * class: sfGoogleAnalyticsFilter
- *
- * # etc ...
- * </code>
+ * Add tracking code to the response.
*
* @package sfGoogleAnalyticsPlugin
* @subpackage filter
* @author Kris Wallsmith <kris.wallsmith@symfony-project.com>
- * @version SVN: $Id: sfGoogleAnalyticsFilter.class.php 11928 2008-10-03 16:59:33Z Kris.Wallsmith $
+ * @version SVN: $Id: sfGoogleAnalyticsFilter.class.php 12235 2008-10-17 16:54:35Z Kris.Wallsmith $
*/
class sfGoogleAnalyticsFilter extends sfFilter
{
/**
* Insert tracking code for applicable web requests.
*
- * @author Kris Wallsmith
* @param sfFilterChain $filterChain
*/
public function execute($filterChain)
{
- if ($this->isTrackable())
+ $prefix = 'app_sf_google_analytics_plugin_';
+ $user = $this->context->getUser();
+ $request = $this->context->getRequest();
+ $response = $this->context->getResponse();
+
+ if ($this->isFirstCall())
{
- // capture custom vars stored to flash on the way up the filter chain
- // since they'll have been removed already on the way down
- sfGoogleAnalyticsToolkit::addCustomVars($this->getContext()->getUser()->getAttributeHolder()->get('google_analytics_custom_vars', array(), 'symfony/flash'));
+ $classes = array_merge(array(
+ 'urchin' => 'sfGoogleAnalyticsTrackerUrchin',
+ 'google' => 'sfGoogleAnalyticsTrackerGoogle'), sfConfig::get($prefix.'classes', array()));
+ $class = $classes[sfConfig::get($prefix.'tracker', 'urchin')];
+
+ $tracker = new $class($this->context);
+
+ // pull callables from session storage
+ $callables = $user->getAttribute('callables', array(), 'sf_google_analytics_plugin');
+ foreach ($callables as $callable)
+ {
+ list($method, $arguments) = $callable;
+ call_user_func_array(array($tracker, $method), $arguments);
+ }
+
+ $request->setTracker($tracker);
}
$filterChain->execute();
+ $tracker = $request->getTracker();
+
+ // apply module- and action-level configuration
+ $module = $this->context->getModuleName();
+ $action = $this->context->getActionName();
- if ($this->isTrackable())
+ $moduleParams = sfConfig::get('mod_'.strtolower($module).'_sf_google_analytics_plugin_params', array());
+ $tracker->configure($moduleParams);
+
+ $actionConfig = sfConfig::get('mod_'.strtolower($module).'_'.$action.'_sf_google_analytics_plugin', array());
+ if (isset($actionConfig['params']))
{
- $insertion = sfConfig::get('app_google_analytics_insertion', 'bottom');
- $insertMethod = 'insertTrackingCode'.$insertion;
-
- if (method_exists($this, $insertMethod))
- {
- if (sfConfig::get('sf_logging_enabled'))
- {
- $this->getContext()->getLogger()->info('{sfGoogleAnalyticsFilter} Inserting tracking code in "'.$insertion.'" position.');
- }
-
- $trackingCode = $this->generateTrackingCode();
- call_user_func(array($this, $insertMethod), "\n".$trackingCode);
- }
- else
+ $tracker->configure($actionConfig['params']);
+ }
+
+ // insert tracking code
+ if ($this->isTrackable() && $tracker->isEnabled())
+ {
+ if (sfConfig::get('sf_logging_enabled'))
{
- throw new sfGoogleAnalyticsException('Unrecognized insertion.');
+ sfGoogleAnalyticsToolkit::logMessage($this, 'Inserting tracking code.');
}
+
+ $tracker->insert($response);
}
elseif (sfConfig::get('sf_logging_enabled'))
{
- $this->getContext()->getLogger()->info('{sfGoogleAnalyticsFilter} Tracking code not inserted.');
+ sfGoogleAnalyticsToolkit::logMessage($this, 'Tracking code not inserted.');
}
+
+ $user->getAttributeHolder()->removeNamespace('sf_google_analytics_plugin');
+ $tracker->shutdown($user);
}
/**
- * Test whether tracking code should be inserted for this request.
+ * Test whether the response is trackable.
*
- * @author Kris Wallsmith
* @return bool
*/
protected function isTrackable()
{
- $context = $this->getContext();
- $request = $context->getRequest();
- $response = $context->getResponse();
- $controller = $context->getController();
+ $request = $this->context->getRequest();
+ $response = $this->context->getResponse();
+ $controller = $this->context->getController();
// don't add analytics:
- // * if google analytics is not enabled
// * for XHR requests
// * if not HTML
// * if 304
// * if not rendering to the client
// * if HTTP headers only
- if (!sfConfig::get('app_google_analytics_enabled') ||
- $request->isXmlHttpRequest() ||
+ if ($request->isXmlHttpRequest() ||
strpos($response->getContentType(), 'html') === false ||
$response->getStatusCode() == 304 ||
$controller->getRenderMode() != sfView::RENDER_CLIENT ||
@@ -101,57 +107,4 @@ protected function isTrackable()
return true;
}
}
-
- /**
- * Insert supplied tracking code at the top of the body tag.
- *
- * @author Kris Wallsmith
- * @param string $trackingCode
- */
- protected function insertTrackingCodeTop($trackingCode)
- {
- $response = $this->getContext()->getResponse();
-
- $oldContent = $response->getContent();
- $newContent = preg_replace('/\<body[^\>]*\>/i', "$0\n".$trackingCode, $oldContent, 1);
-
- if ($oldContent == $newContent)
- {
- $newContent .= $trackingCode;
- }
-
- $response->setContent($newContent);
- }
-
- /**
- * Insert supplied tracking code at the bottom of the body tag.
- *
- * @author Kris Wallsmith
- * @param string $trackingCode
- */
- protected function insertTrackingCodeBottom($trackingCode)
- {
- $response = $this->getContext()->getResponse();
-
- $oldContent = $response->getContent();
- $newContent = str_ireplace('</body>', $trackingCode."\n</body>", $oldContent);
-
- if ($oldContent == $newContent)
- {
- $newContent .= $trackingCode;
- }
-
- $response->setContent($newContent);
- }
-
- /**
- * Get tracking code for insertion.
- *
- * @author Kris Wallsmith
- * @return string
- */
- protected function generateTrackingCode()
- {
- return sfGoogleAnalyticsToolkit::getHtml();
- }
}
View
199 plugins/sfGoogleAnalyticsPlugin/lib/helper/GoogleAnalyticsHelper.php
@@ -1,9 +1,7 @@
<?php
/**
- * A collection of helper functions for attaching analytics tracking code to
- * links. Used for outbound links and downloads. Functions all produce normal
- * links when analytics is turned off in the configuration.
+ * Helpers for sfGoogleAnalyticsPlugin.
*
* @package sfGoogleAnalyticsPlugin
* @subpackage helper
@@ -11,68 +9,205 @@
* @version SVN: $Id: GoogleAnalyticsHelper.php 11928 2008-10-03 16:59:33Z Kris.Wallsmith $
*/
-use_helper('Url', 'Javascript');
+sfLoader::loadHelpers(array('Tag', 'Url'));
/**
- * Build a link that includes a call to the Javascript urchinTracker function.
+ * Build a link that tracks a page view.
*
- * Usually used when linking off your site or to any file on your site that
- * does not include tracking code (i.e. PDF documents, images, etc.)
+ * Options can include:
*
- * @param string $name - name of the link
- * @param string $internalUri - module/action or @rule
- * @param string $urchinUri - custom path for urchinTracker
- * @param array $options - additional HTML parameters
+ * * track_as: an internal URI other than the link's href
+ * * is_route: whether to send the URI through sfRouting
+ * * is_event: track as an event rather than a page view
+ * * use_linker: use this if you're linking to another domain that tracks on
+ * the same website profile
+ *
+ * @param string $name
+ * @param string $internalUri
+ * @param array $options
*
* @return string
*/
-function google_analytics_link_to($name, $internalUri, $urchinUri = null, $options = array())
+function google_analytics_link_to($name = null, $internalUri = null, $options = array())
{
- if (sfConfig::get('app_google_analytics_enabled'))
+ $tracker = sfContext::getInstance()->getRequest()->getTracker();
+
+ $options = _parse_attributes($options);
+ $trackerOptions = $tracker->extractViewOptions($options);
+
+ if ($tracker->isEnabled())
{
- if (!$urchinUri)
+ $trackAs = isset($trackerOptions['track_as']) ? $trackerOptions['track_as'] : $internalUri;
+
+ if (isset($trackerOptions['use_linker']) && $trackerOptions['use_linker'])
+ {
+ $onclick = google_analytics_linker_function($trackAs, $trackerOptions);
+ }
+ else
{
- $urchinUri = url_for($internalUri);
+ $onclick = $tracker->forgePageViewFunction($trackAs, $trackerOptions);
}
- $newOnclick = 'urchinTracker(\''.$urchinUri.'\');';
+ $options['onclick'] = isset($options['onclick']) ? ($onclick.$options['onclick']) : $onclick;
- $options = _parse_attributes($options);
- $options['onclick'] = isset($options['onclick']) ? ($newOnclick.$options['onclick']) : $newOnclick;
+ if (isset($trackerOptions['use_linker']) && $trackerOptions['use_linker'])
+ {
+ $options['onclick'] .= 'return false';
+ }
}
-
+
return link_to($name, $internalUri, $options);
}
/**
- * Build a link to a Javascript call, including a call to urchinTracker.
+ * Build a Javascript link that tracks a page view.
*
- * @param string $name - name of the link
- * @param string $function - Javascript code
- * @param string $urchinUri - custom path for urchinTracker
- * @param array $options - additional HTML parameters
+ * Options can include:
+ *
+ * * track_as: an internal URI (required)
+ * * is_route: whether to send the URI through sfRouting
+ * * is_event: track as an event rather than a page view (for those trackers
+ * that support this option)
+ *
+ * @throws sfViewException if "track_as" option is absent
+ *
+ * @param string $name
+ * @param string $internalUri
+ * @param array $options
*
* @return string
*/
-function google_analytics_link_to_function($name, $function, $urchinUri, $options = array())
+function google_analytics_link_to_function($name, $function, $options = array())
{
+ sfLoader::loadHelpers(array('Javascript'));
+
+ $tracker = sfContext::getInstance()->getRequest()->getTracker();
+
+ $options = _parse_attributes($options);
+ $trackerOptions = $tracker->extractViewOptions($options);
+
$link = link_to_function($name, $function, $options);
+ $link = _add_onclick_tracking($tracker, $link, $trackerOptions);
+
+ return $link;
+}
+
+/**
+ * Build a Javascript link that tracks a page view.
+ *
+ * Options (2nd parameter) can include:
+ *
+ * * track_as: an internal URI (required)
+ * * is_route: whether to send the URI through sfRouting
+ * * is_event: track as an event rather than a page view (for those trackers
+ * that support this option)
+ *
+ * @throws sfViewException if "track_as" option is absent
+ *
+ * @param string $name
+ * @param array $options
+ * @param array $html_options
+ *
+ * @return string
+ */
+function google_analytics_link_to_remote($name, $options = array(), $html_options = array())
+{
+ sfLoader::loadHelpers(array('Javascript'));
+
+ $tracker = sfContext::getInstance()->getRequest()->getTracker();
+
+ $options = _parse_attributes($options);
+ $trackerOptions = $tracker->extractViewOptions($options);
+
+ $link = link_to_remote($name, $options, $html_options);
+ $link = _add_onclick_tracking($tracker, $link, $trackerOptions);
+
+ return $link;
+}
+
+/**
+ * Build a call to the Javascript linker function.
+ *
+ * @param string $url
+ *
+ * @return string
+ */
+function google_analytics_linker_function($url)
+{
+ $tracker = sfContext::getInstance()->getRequest()->getTracker();
+
+ _check_linker_settings($tracker);
+
+ $linker = null;
+ if ($tracker->isEnabled())
+ {
+ $linker = $tracker->forgeLinkerFunction($url);
+ }
+
+ return $linker;
+}
+
+/**
+ * Build a call to the Javascript POST linker function.
+ *
+ * @param string $formElement
+ *
+ * @return string
+ */
+function google_analytics_post_linker_function($formElement = 'this')
+{
+ $tracker = sfContext::getInstance()->getRequest()->getTracker();
+
+ _check_linker_settings($tracker);
- if (sfConfig::get('app_google_analytics_enabled'))
+ $linker = null;
+ if ($tracker->isEnabled())
{
- $link = str_replace('onclick="', 'onclick="urchinTracker(\''.$urchinUri.'\');', $link);
+ $linker = $tracker->forgePostLinkerFunction($formElement);
+ }
+
+ return $linker;
+}
+
+/**
+ * Inserts a page view into the supplied link's onclick attribute.
+ *
+ * @throws sfViewException if "track_as" option is absent
+ *
+ * @param sfGoogleAnalyticsTracker $tracker
+ * @param string $link
+ * @param array $options
+ *
+ * @return string
+ */
+function _add_onclick_tracking(sfGoogleAnalyticsTracker $tracker, $link, $options = array())
+{
+ if (!isset($options['track_as']))
+ {
+ throw new sfViewException(sprintf('{%s} The "track_as" parameter is required.', basename(__FILE__)));
+ }
+
+ $tracker = sfContext::getInstance()->getRequest()->getTracker();
+ if ($tracker->isEnabled())
+ {
+ $onclick = $tracker->forgePageViewFunction($options['track_as'], $options);
+ $onclick = escape_once($onclick);
+
+ $link = str_replace('onclick="', 'onclick="'.$onclick.' ', $link);
}
return $link;
}
/**
- * Add a custom variable to the tracking code.
+ * Confirm the tracker is configured correctly to support a linker.
*
- * @author Kris Wallsmith
- * @param string $var
+ * @param sfGoogleAnalyticsTracker $tracker
*/
-function google_analytics_custom_var($var)
+function _check_linker_settings(sfGoogleAnalyticsTracker $tracker)
{
- sfGoogleAnalyticsToolkit::addCustomVar($var);
+ if ($tracker->getDomainName() !== 'none' || $tracker->getLinkerPolicy() !== true)
+ {
+ sfGoogleAnalyticsToolkit::logMessage(basename(__FILE__), 'If tracking multiple domain names on one profile, the app.yml "domain_name" setting should be "off" and the "linker_policy" setting should be "on".', 'notice');
+ }
}
View
36 plugins/sfGoogleAnalyticsPlugin/lib/listener/sfGoogleAnalyticsListener.class.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * Event listener for sfGoogleAnalyticsPlugin.
+ *
+ * @package sfGoogleAnalyticsPlugin
+ * @subpackage listener
+ * @author Kris Wallsmith <kris.wallsmith@symfony-project.com>
+ * @version SVN: $Id: sfGoogleAnalyticsListener.class.php 11928 2008-10-03 16:59:33Z Kris.Wallsmith $
+ */
+class sfGoogleAnalyticsListener
+{
+ /**
+ * Get the current tracker object.
+ *
+ * @param sfEvent $event
+ *
+ * @return bool
+ */
+ public static function observe(sfEvent $event)
+ {
+ $subject = $event->getSubject();
+
+ switch ($event['method'])
+ {
+ case 'getTracker':
+ $event->setReturnValue(sfGoogleAnalyticsMixin::getTracker($subject));
+ return true;
+
+ case 'setTracker':
+ sfGoogleAnalyticsMixin::setTracker($subject, $event['arguments'][0]);
+ return true;
+ }
+ }
+
+}
View
36 plugins/sfGoogleAnalyticsPlugin/lib/mixin/sfGoogleAnalyticsMixin.class.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * Mixins for sfGoogleAnalyticsPlugin.
+ *
+ * @package sfGoogleAnalyticsPlugin
+ * @subpackage listener
+ * @author Kris Wallsmith <kris.wallsmith@symfony-project.com>
+ * @version SVN: $Id: sfGoogleAnalyticsMixin.class.php 11928 2008-10-03 16:59:33Z Kris.Wallsmith $
+ */
+class sfGoogleAnalyticsMixin
+{
+ /**
+ * Get the current request's tracker object.
+ *
+ * @param mixed $mixable
+ *
+ * @return sfGoogleAnalyticsTracker
+ */
+ public static function getTracker($mixable)
+ {
+ return sfContext::getInstance()->getRequest()->getAttribute('tracker', null, 'sf_google_analytics_plugin');
+ }
+
+ /**
+ * Set the current request's tracker object.
+ *
+ * @param mixed $mixable
+ * @param sfGoogleAnalyticsTracker $tracker
+ */
+ public static function setTracker($mixable, sfGoogleAnalyticsTracker $tracker)
+ {
+ sfContext::getInstance()->getRequest()->setAttribute('tracker', $tracker, 'sf_google_analytics_plugin');
+ }
+
+}
View
945 plugins/sfGoogleAnalyticsPlugin/lib/tracker/sfGoogleAnalyticsTracker.class.php
@@ -0,0 +1,945 @@
+<?php
+
+/**
+ * Houses the core API for manipulating the Google Analytics tracking code.
+ *
+ * @package sfGoogleAnalyticsPlugin
+ * @subpackage tracker
+ * @author Kris Wallsmith <kris.wallsmith@symfony-project.com>
+ * @version SVN: $Id: sfGoogleAnalyticsTracker.class.php 11928 2008-10-03 16:59:33Z Kris.Wallsmith $
+ */
+abstract class sfGoogleAnalyticsTracker
+{
+ const
+ POSITION_TOP = 'top',
+ POSITION_BOTTOM = 'bottom';
+
+ protected
+ $context = null,
+ $parameterHolder = null,
+ $beforeTrackerJS = null,
+ $afterTrackerJS = null,
+
+ $enabled = false,
+ $profileId = null,
+ $insertion = null,
+ $domainName = null,
+ $pageName = null,
+ $linkerPolicy = false,
+ $localRemoteServerPolicy = false,
+ $anchorPolicy = false,
+ $clientInfoPolicy = true,
+ $hashPolicy = true,
+ $detectFlashPolicy = true,
+ $detectTitlePolicy = true,
+ $organicReferers = array(),
+ $ignoredOrganics = array(),
+ $ignoredReferers = array(),
+ $campaignNameKey = null,
+ $campaignSourceKey = null,
+ $campaignMediumKey = null,
+ $campaignTermKey = null,
+ $campaignContentKey = null,
+ $campaignIdKey = null,
+ $campaignNoOverrideKey = null,
+ $sampleRate = null,
+ $sessionTimeout = null,
+ $cookieTimeout = null,
+ $cookiePath = null,
+ $vars = array(),
+ $transaction = null;
+
+ public function __construct($context, $parameters = array())
+ {
+ $this->initialize($context, $parameters);
+ }
+
+ public function initialize($context, $parameters = array())
+ {
+ $this->context = $context;
+
+ $this->parameterHolder = class_exists('sfNamespacedParameterHolder') ? new sfNamespacedParameterHolder : new sfParameterHolder;
+ $this->parameterHolder->add($parameters);
+
+ // apply configuration from app.yml
+ $prefix = 'app_sf_google_analytics_plugin_';
+
+ $params = sfConfig::get($prefix.'params', array());
+ $params['enabled'] = sfConfig::get($prefix.'enabled');
+ $params['profile_id'] = sfConfig::get($prefix.'profile_id');
+ $params['insertion'] = sfConfig::get($prefix.'insertion');
+
+ $this->configure($params);
+
+ return true;
+ }
+
+ /**
+ * Apply non-null configuration values.
+ *
+ * @param array $params
+ */
+ public function configure($params)
+ {
+ $params = array_merge(array(
+ 'enabled' => null,
+ 'insertion' => null,
+ 'profile_id' => null,
+ 'page_name' => null,
+ 'domain_name' => null,
+ 'linker_policy' => null,
+ 'organic_referers' => null,
+ 'vars' => null,
+ 'cookie_path' => null,
+ 'client_info_policy' => null,
+ 'hash_policy' => null,
+ 'detect_flash_policy' => null,
+ 'detect_title_policy' => null,
+ 'session_timeout' => null,
+ 'cookie_timeout' => null,
+ 'campaign_keys' => null,
+ 'anchor_policy' => null,
+ 'ignored_organics' => null,
+ 'ignored_referers' => null,
+ 'sample_rate' => null,
+ 'local_remote_server_policy' => null), $params);
+
+ if (!is_null($params['enabled']))
+ {
+ $this->setEnabled($params['enabled']);
+ }
+
+ if (!is_null($params['profile_id']))
+ {
+ $this->setProfileId($params['profile_id']);
+ }
+
+ if (!is_null($params['page_name']))
+ {
+ $this->setPageName($params['page_name']);
+ }
+
+ if (!is_null($params['insertion']))
+ {
+ $this->setInsertion($params['insertion']);
+ }
+
+ if (!is_null($params['domain_name']))
+ {
+ $this->setDomainName($params['domain_name']);
+ }
+
+ if (!is_null($params['linker_policy']))
+ {
+ $this->setLinkerPolicy($params['linker_policy']);
+ }
+
+ if (!is_null($params['local_remote_server_policy']))
+ {
+ $this->setLocalRemoteServerPolicy($params['local_remote_server_policy']);
+ }
+
+ if (!is_null($params['anchor_policy']))
+ {
+ $this->setAnchorPolicy($params['anchor_policy']);
+ }
+
+ if (!is_null($params['client_info_policy']))
+ {
+ $this->setClientInfoPolicy($params['client_info_policy']);
+ }
+
+ if (!is_null($params['hash_policy']))
+ {
+ $this->setHashPolicy($params['hash_policy']);
+ }
+
+ if (!is_null($params['detect_flash_policy']))
+ {
+ $this->setDetectFlashPolicy($params['detect_flash_policy']);
+ }
+
+ if (!is_null($params['detect_title_policy']))
+ {
+ $this->setDetectTitlePolicy($params['detect_title_policy']);
+ }
+
+ if (!is_null($params['organic_referers']))
+ {
+ foreach ($params['organic_referers'] as $referer)
+ {
+ is_int(key($referer)) ?
+ $this->addOrganicReferer($referer[0], $referer[1]) :
+ $this->addOrganicReferer($referer['name'], $referer['param']);
+ }
+ }
+
+ if (!is_null($params['ignored_organics']))
+ {
+ foreach ($params['ignored_organics'] as $keyword)
+ {
+ $this->addIgnoredOrganic($keyword);
+ }
+ }
+
+ if (!is_null($params['ignored_referers']))
+ {
+ foreach ($params['ignored_referers'] as $referer)
+ {
+ $this->addIgnoredReferer($referer);
+ }
+ }
+
+ if (!is_null($params['campaign_keys']))
+ {
+ foreach ($params['campaign_keys'] as $key => $value)
+ {
+ $method = 'setCampaign'.sfInflector::camelize($key).'Key';
+ $this->$method($value);
+ }
+ }
+
+ if (!is_null($params['sample_rate']))
+ {
+ $this->setSampleRate($params['sample_rate']);
+ }
+
+ if (!is_null($params['session_timeout']))
+ {
+ $this->setSessionTimeout($params['session_timeout']);
+ }
+
+ if (!is_null($params['cookie_timeout']))
+ {
+ $this->setCookieTimeout($params['cookie_timeout']);
+ }
+
+ if (!is_null($params['cookie_path']))
+ {
+ $this->setCookiePath($params['cookie_path']);
+ }
+
+ if (!is_null($params['vars']))
+ {
+ foreach ($params['vars'] as $var)
+ {
+ $this->setVar($var);
+ }
+ }
+ }
+
+ public function getContext()
+ {
+ return $this->context;
+ }
+
+ public function getParameterHolder()
+ {
+ return $this->parameterHolder;
+ }
+
+ public function getParameter($name, $default = null, $ns = null)
+ {
+ return $this->parameterHolder->get($name, $default, $ns);
+ }
+
+ public function hasParameter($name, $ns = null)
+ {
+ return $this->parameterHolder->has($name, $ns);
+ }
+
+ public function setParameter($name, $value, $ns = null)
+ {
+ return $this->parameterHolder->set($name, $value, $ns);
+ }
+
+ /**
+ * Add JS to include immediately before the tracker function is called.
+ *
+ * @param string $js
+ * @param array $options
+ */
+ public function setBeforeTrackerJS($js, $options = array())
+ {
+ if ($this->prepare($js, $options))
+ {
+ $this->beforeTrackerJS = $js;
+ }
+ }
+
+ public function getBeforeTrackerJS()
+ {
+ return $this->beforeTrackerJS;
+ }
+
+ /**
+ * Add JS to include at the bottom of the tracker code.
+ *
+ * @param string $js
+ * @param array $options
+ */
+ public function setAfterTrackerJS($js, $options = array())
+ {
+ if ($this->prepare($js, $options))
+ {
+ $this->afterTrackerJS = $js;
+ }
+ }
+
+ public function getAfterTrackerJS()
+ {
+ return $this->afterTrackerJS;
+ }
+
+ /**
+ * Toggle tracker's enabled state.
+ *
+ * @param bool $enabled
+ */
+ public function setEnabled($enabled)
+ {
+ $this->enabled = (bool) $enabled;
+ }
+
+ public function isEnabled()
+ {
+ return $this->enabled;
+ }
+
+ /**
+ * Set the profile ID to use for this tracker.
+ *
+ * @param string $profileId
+ */
+ public function setProfileId($profileId)
+ {
+ $this->profileId = $profileId;
+ }
+
+ public function getProfileId()
+ {
+ return $this->profileId;
+ }
+
+ /**
+ * Set where the tracking code should be inserted into the response.
+ *
+ * @param string $insertion
+ * @param array $options
+ */
+ public function setInsertion($insertion, $options = array())
+ {
+ if ($this->prepare($insertion, $options))
+ {
+ $this->insertion = $insertion;
+ }
+ }
+
+ public function getInsertion()
+ {
+ return $this->insertion;
+ }
+
+ /**
+ * Define a page other than what's in the address bar.
+ *
+ * @param string $pageName
+ * @param array $options
+ */
+ public function setPageName($pageName, $options = array())
+ {
+ if ($this->prepare($pageName, $options))
+ {
+ $this->pageName = $pageName;
+ }
+ }
+
+ public function getPageName()
+ {
+ return $this->pageName;
+ }
+
+ /**
+ * Set the domain to track this website as.
+ *
+ * @param string $domainName
+ */
+ public function setDomainName($domainName)
+ {
+ if ($domainName === false)
+ {
+ $domainName = 'none';
+ }
+
+ $this->domainName = $domainName;
+ }
+
+ public function getDomainName()
+ {
+ return $this->domainName;
+ }
+
+ /**
+ * Define a linker policy.
+ *
+ * @param bool $enabled
+ */
+ public function setLinkerPolicy($enabled)
+ {
+ $this->linkerPolicy = (bool) $enabled;
+ }
+
+ public function getLinkerPolicy()
+ {
+ return $this->linkerPolicy;
+ }
+
+ /**
+ * Set a transaction to track in the response.
+ *
+ * @param sfGoogleAnalyticsTransaction $transaction
+ * @param array $options
+ */
+ public function setTransaction(sfGoogleAnalyticsTransaction $transaction, $options = array())
+ {
+ if ($this->prepare($transaction, $options))
+ {
+ $this->transaction = $transaction;
+ }
+ }
+
+ public function getTransaction()
+ {
+ return $this->transaction;
+ }
+
+ /**
+ * Add an organic referer.
+ *
+ * @param string $name
+ * @param string $param
+ */
+ public function addOrganicReferer($name, $param)
+ {
+ $this->organicReferers[] = array($name, $param);
+ }
+
+ public function getOrganicReferers()
+ {
+ return $this->organicReferers;
+ }
+
+ /**
+ * Add a custom tracking variable to this cookie.
+ *
+ * @param string $var
+ * @param array $options
+ */
+ public function setVar($var, $options = array())
+ {
+ if ($this->prepare($var, $options))
+ {
+ $this->vars[] = $var;
+ }
+ }
+
+ public function getVars()
+ {
+ return $this->vars;
+ }
+
+ /**
+ * Set a path to limit the tracking cookie to.
+ *
+ * @param string $path
+ * @param array $options
+ */
+ public function setCookiePath($path, $options = array())
+ {
+ if ($this->prepare($path, $options))
+ {
+ $this->cookiePath = $path;
+ }
+ }
+
+ public function getCookiePath()
+ {
+ return $this->cookiePath;
+ }
+
+ /**
+ * Define a client info detection policy.
+ *
+ * @param bool $enabled
+ */
+ public function setClientInfoPolicy($enabled)
+ {
+ $this->clientInfoPolicy = (bool) $enabled;
+ }
+
+ public function getClientInfoPolicy()
+ {
+ return $this->clientInfoPolicy;
+ }
+
+ /**
+ * Define a hash policy.
+ *
+ * @param bool $enabled
+ */
+ public function setHashPolicy($enabled)
+ {
+ $this->hashPolicy = (bool) $enabled;
+ }
+
+ public function getHashPolicy()
+ {
+ return $this->hashPolicy;
+ }
+
+ /**
+ * Define a flash detection policy.
+ *
+ * @param bool $enabled
+ */
+ public function setDetectFlashPolicy($enabled)
+ {
+ $this->detectFlashPolicy = (bool) $enabled;
+ }
+
+ public function getDetectFlashPolicy()
+ {
+ return $this->detectFlashPolicy;
+ }
+
+ /**
+ * Define a title detection policy.
+ *
+ * @param bool $enabled
+ */
+ public function setDetectTitlePolicy($enabled)
+ {
+ $this->detectTitlePolicy = $enabled;
+ }
+
+ public function getDetectTitlePolicy()
+ {
+ return $this->detectTitlePolicy;
+ }
+
+ /**
+ * Set a session timeout.
+ *
+ * @param int $seconds
+ */
+ public function setSessionTimeout($seconds)
+ {
+ $this->sessionTimeout = (int) $seconds;
+ }
+
+ public function getSessionTimeout()
+ {
+ return $this->sessionTimeout;
+ }
+
+ /**
+ * Set a cookie timeout.
+ *
+ * @param int $seconds
+ */
+ public function setCookieTimeout($seconds)
+ {
+ $this->cookieTimeout = (int) $seconds;
+ }
+
+ public function getCookieTimeout()
+ {
+ return $this->cookieTimeout;
+ }
+
+ /**
+ * Set a campaign name parameter key.
+ *
+ * @param string $key
+ */
+ public function setCampaignNameKey($key)
+ {
+ $this->campaignNameKey = $key;
+ }
+
+ public function getCampaignNameKey()
+ {
+ return $this->campaignNameKey;
+ }
+
+ /**
+ * Set a campaign source parameter key.
+ *
+ * @param string $key
+ */
+ public function setCampaignSourceKey($key)
+ {
+ $this->campaignSourceKey = $key;
+ }
+
+ public function getCampaignSourceKey()
+ {
+ return $this->campaignSourceKey;
+ }
+
+ /**
+ * Set a campaign medium parameter key.
+ *
+ * @param string $key
+ */
+ public function setCampaignMediumKey($key)
+ {
+ $this->campaignMediumKey = $key;
+ }
+
+ public function getCampaignMediumKey()
+ {
+ return $this->campaignMediumKey;
+ }
+
+ /**
+ * Set a campaign term parameter key.
+ *
+ * @param string $key
+ */
+ public function setCampaignTermKey($key)
+ {
+ $this->campaignTermKey = $key;
+ }
+
+ public function getCampaignTermKey()
+ {
+ return $this->campaignTermKey;
+ }
+
+ /**
+ * Set a campaign content parameter key.
+ *
+ * @param string $key
+ */
+ public function setCampaignContentKey($key)
+ {
+ $this->campaignContentKey = $key;
+ }
+
+ public function getCampaignContentKey()
+ {
+ return $this->campaignContentKey;
+ }
+
+ /**
+ * Set a campaign ID parameter key.
+ *
+ * @param string $key
+ */
+ public function setCampaignIdKey($key)
+ {
+ $this->campaignIdKey = $key;
+ }
+
+ public function getCampaignIdKey()
+ {
+ return $this->campaignIdKey;
+ }
+
+ /**
+ * Set a campaign no override parameter key.
+ *
+ * @param string $key
+ */
+ public function setCampaignNoOverrideKey($key)
+ {
+ $this->campaignNoOverrideKey = $key;
+ }
+
+ public function getCampaignNoOverrideKey()
+ {
+ return $this->campaignNoOverrideKey;
+ }
+
+ /**
+ * Define an anchor policy.
+ *
+ * @param bool $enabled
+ */
+ public function setAnchorPolicy($enabled)
+ {
+ $this->anchorPolicy = (bool) $enabled;
+ }
+
+ public function getAnchorPolicy()
+ {
+ return $this->anchorPolicy;
+ }
+
+ /**
+ * Add an ignored orgnic keyword.
+ *
+ * @param string $keyword
+ */
+ public function addIgnoredOrganic($keyword)
+ {
+ $this->ignoredOrganics[] = $keyword;
+ }
+
+ public function getIgnoredOrganics()
+ {
+ return $this->ignoredOrganics;
+ }
+
+ /**
+ * Add an ignored referer.
+ *
+ * @param string $referer
+ */
+ public function addIgnoredReferer($referer)
+ {
+ $this->ignoredReferers[] = $referer;
+ }
+
+ public function getIgnoredReferers()
+ {
+ return $this->ignoredReferers;
+ }
+
+ /**
+ * Set a sample rate.
+ *
+ * @param int $rate
+ */
+ public function setSampleRate($rate)
+ {
+ $this->sampleRate = (int) $rate;
+ }
+
+ public function getSampleRate()
+ {
+ return $this->sampleRate;
+ }
+
+ /**
+ * Define a local/remove server policy.
+ *
+ * @param bool $enabled
+ */
+ public function setLocalRemoteServerPolicy($enabled)
+ {
+ $this->localRemoteServerPolicy = (bool) $enabled;
+ }
+
+ public function getLocalRemoteServerPolicy()
+ {
+ return $this->localRemoteServerPolicy;
+ }
+
+ /**
+ * Extract options used by tracker's helper functions.
+ *
+ * View options include:
+ *
+ * * track_as
+ * * is_route
+ * * is_event
+ * * use_linker
+ *
+ * @param array $options
+ *
+ * @return array
+ */
+ public function extractViewOptions(& $options)
+ {
+ $viewOptions = array();
+
+ foreach (array('track_as', 'is_route', 'is_event', 'use_linker') as $option)
+ {
+ if (isset($options[$option]))
+ {
+ $viewOptions[$option] = $options[$option];
+ unset($options[$option]);
+ }
+ }
+
+ return $viewOptions;
+ }
+
+ /**
+ * Forge a call to the Javascript page view function.
+ *
+ * @param string $path
+ * @param array $options
+ *
+ * @return string
+ */
+ abstract public function forgePageViewFunction($path = null, $options = array());
+
+ /**
+ * Forge a call to the Javascript linker function.
+ *
+ * @param string $path
+ *
+ * @return string
+ */
+ abstract public function forgeLinkerFunction($url);
+
+ /**
+ * Forge a call to the Javascript POST linker function.
+ *
+ * @param string $formElement
+ *
+ * @return string
+ */
+ abstract public function forgePostLinkerFunction($formElement = 'this');
+
+ /**
+ * Insert tracking code into a response.
+ *
+ * @param sfResponse $response
+ */
+ abstract public function insert(sfResponse $response);
+
+ /**
+ * Insert content into a response.
+ *
+ * @param sfResponse $response
+ * @param string $content
+ * @param string $position
+ */
+ protected function doInsert(sfResponse $response, $content, $position = null)
+ {
+ if ($position == null)
+ {
+ $position = self::POSITION_BOTTOM;
+ }
+
+ // check for overload
+ $method = 'doInsert'.$position;
+
+ if (method_exists($this, $method))
+ {
+ call_user_func(array($this, $method), $response, $content);
+ }
+ else
+ {
+ $old = $response->getContent();
+
+ switch ($position)
+ {
+ case self::POSITION_TOP:
+ $new = preg_replace('/<body[^>]*>/i', "$0\n".$content."\n", $old, 1);
+ break;
+
+ case self::POSITION_BOTTOM:
+ $new = str_ireplace('</body>', "\n".$content."\n</body>", $old);
+ break;
+ }
+
+ if ($old == $new)
+ {
+ $new .= $content;
+ }
+
+ $response->setContent($new);
+ }
+ }
+
+ /**
+ * Apply common options to a value.
+ *
+ * @param mixed $value
+ * @param mixed $options
+ *
+ * @return bool whether to continue execution
+ */
+ protected function prepare(& $value, & $options = array())
+ {
+ if (is_string($options))
+ {
+ $options = sfToolkit::stringToArray($options);
+ }
+
+ if (isset($options['use_flash']) && $options['use_flash'])
+ {
+ unset($options['use_flash']);
+
+ $trace = debug_backtrace();
+
+ $caller = $trace[1];
+ $this->plant($caller['function'], array($value, $options));
+
+ return false;
+ }
+ else
+ {
+ if (is_string($value) && isset($options['is_route']) && $options['is_route'])
+ {
+ $value = $this->context->getController()->genUrl($value);
+ unset($options['is_route']);
+ }
+
+ return true;
+ }
+ }
+
+ /**
+ * Plant a callable to be executed against the next request's tracker.
+ *
+ * @param string $method
+ * @param array $arguments
+ */
+ protected function plant($method, $arguments = array())
+ {
+ if (sfConfig::get('sf_logging_enabled'))
+ {
+ sfGoogleAnalyticsToolkit::logMessage($this, 'Storing call to %s method for next response.');
+ }
+
+ $callables = $this->parameterHolder->getAll('flash', array());
+ $callables[] = array($method, $arguments);
+
+ $this->parameterHolder->removeNamespace('flash');
+ $this->parameterHolder->add($callables, 'flash');
+ }
+
+ /**
+ * Escape the provided value for Javascript evaluation.
+ *
+ * @param string $value
+ *
+ * @return string
+ */
+ protected function escape($value)
+ {
+ if (function_exists('json_encode'))
+ {
+ $escaped = json_encode($value);
+ }
+ else
+ {
+ sfLoader::loadHelpers(array('Escaping'));
+ $escaped = '"'.esc_js($value).'"';
+ }
+
+ return $escaped;
+ }
+
+ /**
+ * Update storage with callables for the next tracker.
+ *
+ * @param sfUser $user
+ */
+ public function shutdown($user)
+ {
+ if (sfConfig::get('sf_logging_enabled'))
+ {
+ sfGoogleAnalyticsToolkit::logMessage($this, 'Copying callables to session storage.');
+ }
+
+ $user->getAttributeHolder()->set('callables', $this->parameterHolder->getAll('flash', array()), 'sf_google_analytics_plugin');
+ }
+
+}
View
242 plugins/sfGoogleAnalyticsPlugin/lib/tracker/sfGoogleAnalyticsTrackerGoogle.class.php
@@ -0,0 +1,242 @@
+<?php
+
+/**
+ * Google Analytics ga.js tracker.
+ *
+ * @package sfGoogleAnalyticsPlugin
+ * @subpackage tracker
+ * @author Kris Wallsmith <kris.wallsmith@symfony-project.com>
+ * @version SVN: $Id: sfGoogleAnalyticsTrackerGoogle.class.php 11928 2008-10-03 16:59:33Z Kris.Wallsmith $
+ */
+class sfGoogleAnalyticsTrackerGoogle extends sfGoogleAnalyticsTracker
+{
+ protected
+ $trackerVar = 'pageTracker';
+
+ public function configure($params)
+ {
+ parent::configure($params);
+
+ $params = array_merge(array(
+ 'tracker_var' => null), $params);
+
+ if (!is_null($params['tracker_var']))
+ {
+ $this->setTrackerVar($params['tracker_var']);
+ }
+ }
+
+ public function setTrackerVar($tracker)
+ {
+ $this->trackerVar = $tracker;
+ }
+ public function getTrackerVar()
+ {
+ return $this->trackerVar;
+ }
+
+ /**
+ * @see sfGoogleAnalyticsTracker
+ */
+ public function insert(sfResponse $response)
+ {
+ $tracker = $this->getTrackerVar();
+
+ $html = array();
+ $html[] = '<script type="text/javascript">';
+ $html[] = '//<![CDATA[';
+ $html[] = 'var gaJsHost=(("https:"==document.location.protocol)?"https://ssl.":"http://www.");';
+ $html[] = 'document.write(unescape("%3Cscript src=\'"+gaJsHost+"google-analytics.com/ga.js\' type=\'text/javascript\'%3E%3C/script%3E"));';
+ $html[] = '//]]>';
+ $html[] = '</script>';
+ $html[] = '<script type="text/javascript">';
+ $html[] = '//<![CDATA[';
+
+ $html[] = sprintf('var %s=_gat._getTracker(%s);', $tracker, $this->escape($this->getProfileId()));
+ $html[] = sprintf('%s._initData();', $tracker);
+
+ if ($domainName = $this->getDomainName())
+ {
+ $html[] = sprintf('%s._setDomainName(%s);', $tracker, $this->escape($domainName));
+ }
+
+ if ($this->getLinkerPolicy())
+ {
+ $html[] = sprintf('%s._setAllowLinker(true);', $tracker);
+ }
+
+ foreach ($this->getOrganicReferers() as $i => $referer)
+ {
+ list($name, $param) = $referer;
+
+ $html[] = sprintf('%s._addOrganic(%s, %s);', $tracker, $this->escape($name), $this->escape($param));
+ }
+
+ if ($cookiePath = $this->getCookiePath())
+ {
+ $html[] = sprintf('%s._setCookiePath(%s);', $tracker, $this->escape($cookiePath));
+ }
+
+ // data collection
+ if (!$this->getClientInfoPolicy())
+ {
+ $html[] = sprintf('%s._setClientInfo(false);', $tracker);
+ }
+ if (!$this->getHashPolicy())
+ {
+ $html[] = sprintf('%s._setAllowHash(false);', $tracker);
+ }
+ if (!$this->getDetectFlashPolicy())
+ {
+ $html[] = sprintf('%s._setDetectFlash(false);', $tracker);
+ }
+ if (!$this->getDetectTitlePolicy())
+ {
+ $html[] = sprintf('%s._setDetectTitle(false);', $tracker);
+ }
+
+ if ($timeout = $this->getSessionTimeout())
+ {
+ $html[]