Skip to end of metadata
Go to start of metadata

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[]]></ac:plain-text-body></ac:macro>
<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

Zend Framework: Zend_Http_UserAgent (was Zend_Browser) Component Proposal

Proposed Component Name Zend_Http_UserAgent (was Zend_Browser)
Developer Notes http://framework.zend.com/wiki/display/ZFDEV/Zend_Http_UserAgent (was Zend_Browser)
Proposers Raphaël Carles
Zend Liaison  
Revision 1.0 - 03 August 2010: Initial Draft. (wiki revision: 13)

Table of Contents

1. Overview

This proposition covers several classes dedicated to the client browser/device detection and the available associated features and capabilities.
Its aim is to provide an interface to devices identification libraries like WURFL or DeviceAtlas and ease browsers differences handling, including mobile browsers.
This normalization of client environment detection can ease the management of multi-support development.

2. References

3. Component Requirements, Constraints, and Acceptance Criteria

  • This component will allow quick detection of browsers, using per-session storage of last identification data
  • This component will ease the use of external device identification libraries
  • This component will be lightweight by using singleton pattern
  • This component will provide an easy way to include new browsers types to detect.
  • This component will not provide content adaptation/content replacement mechanisms or helpers

4. Dependencies on Other Framework Components

  • Zend_Session (optional)

5. Theory of Operation

The UserAgent component should be seen as an information provider to Zend Framework applications at any level (helpers, controllers...)

Detection relies on declared or forced user agent information from server vars. It allows to have a standard behavior in the case that user agent string is present, a default one otherwise, and a forced mode where user agent is given at call time.

The identification class has a declared list of browsers types, ordered by priority.
Priorities can be changed to reflect application orientation (eg. a mobile-oriented website should have a faster identification of mobile devices than desktop ones).
New browser types can be developed and added to the priority list (or to extend an existing one), allowing wider recognition (probes, text browsers, ...) for the application that uses it.

The identification function is not called directly, although this is also possible.
All calls should be done to the getInstance method to execute the full identification process only one time per-request, or if session is activated, one time per-session and user agent.

After a quick detection of browser type, Zend_UserAgent can populate features by two ways :

  • by responding directly to features checks (eg. return false to every request for a text browser, return true to every request for a desktop browser)
  • by delegating to a Zend_UserAgent_Features_Adapter that will retrieve features.

The result is then stored as mentioned to bypass identification at next call (unless another user agent is forced).

6. Milestones / Tasks

Component already done for specific developments without ZF.

  • Milestone 1: refactoring of existing code and adpatations to ZF design standards
  • Milestone 2: Working prototype checked into the incubator supporting use cases #1, #2, ...
  • Milestone 3: Working prototype checked into the incubator supporting use cases #3 and #4.
  • Milestone 4: Unit tests exist, work, and are checked into SVN.
  • Milestone 5: Initial documentation exists.

7. Class Index

  • Zend_UserAgent
  • Zend_UserAgent_AbstractUserAgent
  • Zend_UserAgent_Mobile
  • Zend_UserAgent_Tablet
  • Zend_UserAgent_Desktop (by default)
  • Zend_UserAgent_Bot
  • Zend_UserAgent_Text
  • Zend_UserAgent_Features_Adapter
  • Zend_UserAgent_Features_Adapter_WurflPhpApi (the first adapter to be provided)
  • Zend_UserAgent_Features_Adapter_Wurfl
  • Zend_UserAgent_Features_Adapter_TeraWurfl
  • Zend_UserAgent_Features_Adapter_DeviceAtlas
  • Zend_UserAgent_Storage
  • Zend_UserAgent_Storage_NonPersistent
  • Zend_UserAgent_Storage_Session

The first adapter provided will be Zend_UserAgent_Features_Adapter_WurflPhpApi http://wurfl.sourceforge.net/nphp/

8. Use Cases

9. Class Skeletons

]]></ac:plain-text-body></ac:macro>

]]></ac:plain-text-body></ac:macro>

Labels:
proposal proposal Delete
browser browser Delete
user-agent user-agent Delete
mobile mobile Delete
wurfl wurfl Delete
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Aug 03, 2010

    <p>Wouldn't it be better to implement this as a viewhelper?</p>

    1. Aug 09, 2010

      <p>Not necessarily. It's often good to get the browser capability detection <em>before</em> any views or layouts are rendered, as it allows you to choose which ones you want to use. (Think ContextSwitch here – browser detection can be used instead of an XHR header or a "format" query parameter.)</p>

    2. Aug 18, 2010

      <p>The aim of this component is to provide the necessary informations to make conditional code for multi support display (and of course for the mobile support which is the most relevant target). </p>

      <p>This adaptation can be done before or after the view rendering.</p>

      <p>As a standalone component it can be anyway used as a viewhelper.</p>

  2. Aug 04, 2010

    <p>Hello,</p>

    <p>i wanted to start also this proposal today, but it seems that u we're faster <ac:emoticon ac:name="smile" /></p>

    <p>I think the name of the class is "wrong", it thould be "Zend_User" or something like that, because the information is not only from the browser:</p>
    <ul>
    <li>OS</li>
    <li>Resolution</li>
    <li>...</li>
    </ul>

  3. Aug 05, 2010

    <p>Hi,</p>

    <p>I agree with Martin Keckeis.<br />
    By the way, as the extending class are not only browser, UserAgent could be appropriate.</p>

    1. Aug 09, 2010

      <p>UserAgent makes sense as a name to me. "User" is too short and ambiguous; browser is perhaps too narrow.</p>

      1. Aug 18, 2010

        <p>Everyone seems to agree for "Zend_UserAgent".</p>

        <p>I will update the Class Index to :</p>

        <p>•Zend_UserAgent</p>

        <p>•Zend_UserAgent_Abstract<br />
        •Zend_UserAgent_Bot<br />
        •Zend_UserAgent_Checker<br />
        •Zend_UserAgent_Console<br />
        •Zend_UserAgent_Desktop (by default)<br />
        •Zend_UserAgent_Email<br />
        •Zend_UserAgent_Feed<br />
        •Zend_UserAgent_Mobile<br />
        •Zend_UserAgent_Offline<br />
        •Zend_UserAgent_Spam<br />
        •Zend_UserAgent_Tablet<br />
        •Zend_UserAgent_Text<br />
        •Zend_UserAgent_Validator<br />
        (inspired by the lists provided by <a class="external-link" href="http://www.useragentstring.com/pages/useragentstring.php">http://www.useragentstring.com/pages/useragentstring.php</a> and <a class="external-link" href="http://user-agent-string.info/list-of-ua">http://user-agent-string.info/list-of-ua</a>)</p>

        <p>•Zend_UserAgent_Features_Adapter_WurflApi (the first adapter to be provided)<br />
        •Zend_UserAgent_Features_Adapter_DeviceAtlas<br />
        •Zend_UserAgent_Features_Adapter_Interface<br />
        •Zend_UserAgent_Features_Adapter_TeraWurfl<br />
        •Zend_UserAgent_Features_Adapter_Wurfl</p>

        <p>NOTE : the "Features" classes must be independant on user-agent's type because, for example, the Wurfl API can provide capabilities for mobile/desktop/bot and spider browsers (see <a class="external-link" href="http://dev.wurflpro.com/projects/wurfl-api/browser/php/core/trunk/examples/resources/web_browsers_patch.xml">http://dev.wurflpro.com/projects/wurfl-api/browser/php/core/trunk/examples/resources/web_browsers_patch.xml</a> and <a class="external-link" href="http://dev.wurflpro.com/projects/wurfl-api/browser/php/core/trunk/examples/resources/bots_and_spider.xml">http://dev.wurflpro.com/projects/wurfl-api/browser/php/core/trunk/examples/resources/bots_and_spider.xml</a>).</p>

  4. Aug 19, 2010

    <p>The proposer should note that all future proposals should target Zend Framework 2.0 since ZF 1.11 will be the final release accepting new features in the 1.x branch. ZF 1.x proposals cannot be reviewed until they are updated accordingly. For your information, Zend Framework 2.0 is written for PHP 5.3 and utilises namespaces - updating code for this is not as hard as it seems <ac:emoticon ac:name="wink" />.</p>

    <p>Paddy</p>

    <p>Community Review (CR) Team </p>

    1. Aug 19, 2010

      <p>Actually, Paddy – this is a Zend partner, and they have agreed to be able to prepare the proposal and code in time for 1.11. I'd like to discuss this with the CR-Team today, if possible.</p>

  5. Aug 20, 2010

    <p>I'd suggest to rename the component to Zend_Http_UserAgent.</p>

  6. Aug 24, 2010

    <ac:macro ac:name="note"><ac:rich-text-body><p><strong>Community Review Team Recommendation</strong></p>

    <p>The CR Team recommends this component be included into versions 1.11 and 2.0 of the Zend Framework with the following requirements:</p>
    <ul>
    <li>The component be put in the Zend_Http_UserAgent namespace</li>
    <li>The component should not be a singleton, instead it should be accompanied with a Zend_Application Resource Plugin that instantiates it and stores it inside Zend_Application's DI-container, and then can be retrieved from there using a viewhelper.</li>
    <li>The component should be accompanied with a method to clear its session (to assist in testing).</li>
    <li>If the component is dependent on external libraries their license should be compatible with the one ZF is shipped with.</li>
    </ul>
    </ac:rich-text-body></ac:macro>

    1. Sep 17, 2010

      <p>Hi, CR-Team.</p>

      <p>Is there any reason which should be renaming to Zend_Http_UserAgent?</p>

      <p>Currently, Zend_Http_* is a side where sending request.Zend_Http_* should be no where request is received?</p>

      1. Sep 18, 2010

        <p>This functionality of the proposed component is not restricted to use in the MVC, but falls under the HTTP protocol (as a combination of HTTP request headers are inspected). </p>

        <p>Zend_Http has primarily been an area of the Client in the past. However, it was never intended to be <em>only</em> for HTTP client purposes; at one point, a Server was considered. As such, this is a perfect location for this new component.</p>

  7. Sep 17, 2010

    <p>I think that these classes should be written to be cooperate with the Zend_Controller_Request_Http and User's Controller_Request_HttpTestCase. </p>

    <p>So, I propose a defining proxy-class, instead of $_SERVER. as follows.</p>

    <ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
    abstract class Zend_Http_UserAgent_AbstractUserAgent
    {
    private $_serverVar;

    //@return Zend_Http_UserAgent_ServerVar
    public function getServer()
    {
    if (!$this->_server)

    Unknown macro: { $this->_server = new Zend_Http_UserAgent_ServerVar; }

    return $_server;
    }

    public function setServer(Zend_Http_UserAgent_ServerVar $serverVar)

    Unknown macro: { $this->_server = $serverVar; }

    }
    ]]></ac:plain-text-body></ac:macro>

    <ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
    class Zend_Http_UserAgent_ServerVar implements ArrayAccess
    {
    private $_server;

    public function __construct($request = null)
    {
    if ($request instanceof Zend_Controller_Request_Http)

    Unknown macro: { $this->_server = $request->getServer(); $this->_request = $request; }

    elseif (is_array($request))

    Unknown macro: { $this->_server = $request; }

    else

    Unknown macro: { $this->_server = $_SERVER; }

    }
    }
    ]]></ac:plain-text-body></ac:macro>

    <p>current code will be change as follows?<br />
    if (isset ( $_SERVER <ac:link><ri:page ri:content-title=""REMOTE_ADDR"" /></ac:link> )) {<br />
    ?<br />
    $server = $this->getServer();<br />
    if (isset ( $server<ac:link><ri:page ri:content-title=""REMOTE_ADDR"" /></ac:link> )) {</p>

    1. Sep 18, 2010

      <p>There's no reason to tie it to Zend_Controller_Request_Http at all. That class has a getServer() method already, and the return of that may be passed in to Zend_Http_UserAgent to introspect.</p>