Skip to content

Every example ends with Find out more, and gives the tagged links it needs - #98

Merged
jwrosewell merged 3 commits into
rcfrom
fix/examples-find-out-more
Nov 14, 2026
Merged

jwrosewell merged 3 commits into
rcfrom
fix/examples-find-out-more

Conversation

@jwrosewell

@jwrosewell jwrosewell commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

Every example in this repository now ends with a "Find out more" section, gives the tagged links it needs when no resource key is set, and the readmes and AGENTS.md describe the examples as they are. This draft covers the examples gaps DX-php-20, DX-php-30, DX-php-31, DX-php-33, DX-php-34, DX-php-35, DX-php-36, DX-php-37, DX-php-38 and DX-php-39.

The problem

Each gap, with file and line at rc 6d95eeee.

  1. DX-php-33, console examples. No console example printed a Find out more section. The words appeared in three example files only, all web pages (device-detection/onpremise/examples/onpremise/static/page.php line 219, ip-intelligence/examples/cloud/web-mixed/index.php line 262 and pipeline/did/examples/creator-context-web/page.html line 143).
  2. DX-php-34, web pages. Seven web pages had none: the Device Detection on-premise userAgentClientHints-Web.php, the Device Detection cloud static/page.php and userAgentClientHints-Web.php, the IP Intelligence onpremise/web, onpremise/web-mixed and cloud/web pages, and the location webIntegration.php.
  3. DX-php-35, a GitHub tag on printed links. Three IP Intelligence cloud console examples printed their configuration page link tagged utm_source=github (gettingstarted-console.php line 34, and the same line of metadata-console.php and getallproperties-console.php).
  4. DX-php-36, the deprecated key name. Messages and documents told people to set resource_key, although the code reads _51DEGREES_RESOURCE_KEY first: the four IP Intelligence cloud console examples (line 34 of each), cloud/web/index.php line 118, cloud/web-mixed/index.php line 70, location/readme.md line 51, ip-intelligence/readme.md line 158, ip-intelligence/ci/README.md line 35, AGENTS.md line 198, the comment at ip-intelligence/ci/run-integration-tests.ps1 line 9, and two skip messages and a comment in ip-intelligence/tests (ExampleTests.php line 113, IpIntelligenceCloudTests.php lines 175 and 185).
  5. DX-php-37, a fatal error. location/examples/index.php lines 41 to 46 called $this->fail(...) at file scope when no key was set, which only works inside location/tests/ExampleTests.php. It is the page served as / by the web server location/readme.md starts, and run with no key it stopped with "Uncaught Error: Using $this when not in object context", as the red run below shows.
  6. DX-php-38, no link to create a key. ip-intelligence/examples/cloud/mixed/gettingstarted-console.php line 34 and pipeline/did/examples/creator-context-web/server.php lines 126 to 129 gave no link when no key was set, where every other cloud example links the configuration page.
  7. DX-php-31, no Enterprise property. The Device Detection on-premise failureToMatch.php and manualDataUpdate.php read only IsMobile, so on the Lite file they showed no Enterprise only property and gave no contact link.
  8. DX-php-20, a relative link. The match metrics example printed /documentation/4.5/_device_detection__hash.html#... (classes/MatchMetrics.php lines 127 to 129), which a console reader cannot follow, and matchMetrics.php lines 30 and 31 had two more in the doc comment.
  9. DX-php-30, the readme's start command. device-detection/onpremise/readme.md lines 171 to 182 said to run composer install at the repository root and then php -S localhost:3000 gettingStartedWeb.php from the examples folder. The script is examples/onpremise/gettingStartedWeb.php, and the examples load the package's own vendor/autoload.php (gettingStartedConsole.php line 37), which the root install does not create (AGENTS.md lines 203 to 206).
  10. DX-php-39, AGENTS.md out of date. Lines 226 to 229 said CI runs the examples' classes and "not the example scripts", while both ExamplesWithoutSettingsTests run the scripts in their own PHP, and lines 145 to 170 left out the Enterprise lines and said the missing IP Intelligence properties read (not available - ...), while the examples print "needs the Enterprise data file".

What the specification says

The Device Detection required examples at c8128ca4, lines 20 to 23:

Those tests MUST include a run of each example with no arguments or settings, as someone would run it from a fresh clone, so that the run uses the free data files.

Lines 101 to 113:

Alongside Properties the Lite Data File holds, an example asks for Properties that only the Enterprise Data File holds, such as HardwareVendor, HardwareName and DeviceType. Where the data file in use has no value for one of them, the example says that the Property needs the Enterprise Data File, rather than leaving it out or showing a default value, and once in its output gives a link to the 51Degrees contact page to ask for a copy. The link the example writes carries utm_source=code, utm_medium=example, the language repository's name as utm_campaign and the example's file as utm_content, so that an enquiry can be traced to the example that prompted it.

Lines 115 to 117:

An example whose purpose needs the Enterprise Data File or a License Key, such as one that updates the data file, explains that when it runs with the Lite Data File, gives the same link, and completes without failure.

Lines 129 to 133, for the cloud examples:

Reference implementation examples illustrate use of Resource Keys to access the cloud service. A predefined link such as this one can be created to create a Resource Key to provide access to the Properties used in the examples.

The IP Intelligence required examples, lines 80 to 91, apply the same rules to the IP Intelligence examples. The specification does not define the Find out more section. That is 51Degrees' rule for every example, which ends with a clearly separated "Find out more" section listing the engine repositories as bare addresses and 51degrees.com pages tagged as above. This repository has no .utm-lint.json, so common-ci's link lint decides the tag format, being "Exactly the five parameters above, in that order, each once", with utm_content and utm_term as lowercase slugs and the term at most 60 characters (scripts/utm-lint.ps1 lines 11 to 18 at 1c5c0e0b).

What changed and why

One helper per package. Each package that has an examples helper class gets one set of methods for the section, so the examples all say the same thing and no example carries its own copy: ExampleUtils in Device Detection on-premise, ExampleUtils in Device Detection cloud, ExampleUtils in IP Intelligence and Constants in location. getFindOutMore gives the section as text, a blank line, the heading "Find out more" underlined with hyphens, then one label: address line per link. getFindOutMoreHtml gives the same list for the foot of a web page, and printFindOutMore writes the text from the command line and the list from a web server. The repositories are bare addresses, being this repository's package folder and, for Device Detection on-premise and IP Intelligence, 51degrees-cxx and the data repository. The 51degrees.com pages are the product page (both products for IP Intelligence, whose mixed examples use device detection as well), the resource key documentation where the package has cloud examples, pricing and contact, each built by getTaggedLink with utm_source=code&utm_medium=example&utm_campaign=51degrees-php, the example's path from its package folder as utm_content (for example examples-onpremise-gettingstartedconsole.php, as the examples' existing links name it) and a find-out-more-... term. The two pipeline core examples and the two 51Did examples have no such class, so each writes its own short section. The hand-written sections in device-detection/onpremise/examples/onpremise/static/page.php and ip-intelligence/examples/cloud/web-mixed/index.php now come from the helper too, and pipeline/did/examples/creator-context-web/page.html is unchanged.

Every clean end prints it. Every console example ends with it, after its last result. A cloud example run with no resource key prints its message and the section before it stops, and the location examples print it at each early return as well (no key, no configuration file, no Device Detection package, missing properties). Web pages show it as their last visible section, also when the page shows an error box. The routes that answer /51Degrees.core.js and /json get nothing added. In Device Detection cloud, ExampleUtils::logErrorAndExit takes the example's file as a new optional third argument and prints the section before it exits. ghev-to-http.php loads ExampleUtils.php by itself, so it still needs no composer install.

Links and names (DX-php-35, DX-php-36, DX-php-38). The four IP Intelligence cloud console examples name _51DEGREES_RESOURCE_KEY and give the configuration page tagged utm_source=code&utm_medium=example with the example's path as utm_content, the mixed one included. The two IP Intelligence cloud web pages name _51DEGREES_RESOURCE_KEY in their error box and link the configuration page from it. The 51Did creator context server, given no key, still answers HTTP 500, now with a page that names _51DEGREES_RESOURCE_KEY, links the configuration page and ends with the section. The readmes, ip-intelligence/ci/README.md, the comment in ip-intelligence/ci/run-integration-tests.ps1, two test skip messages, one test comment and AGENTS.md name _51DEGREES_RESOURCE_KEY. The code still reads resource_key when _51DEGREES_RESOURCE_KEY is unset or empty, as a deprecated name, because a patch release never removes a public name.

The location index page (DX-php-37). With no key, location/examples/index.php says that the page gets its JavaScript from the 51Degrees cloud service, which needs a resource key to know which properties to return, gives the tagged configuration page link, names _51DEGREES_RESOURCE_KEY, prints the section and returns. location/tests/ExampleTests.php, which includes the page with a key, now says the key is missing when the page gives no JavaScript, rather than reading an unset variable.

Enterprise properties (DX-php-31). The on-premise failureToMatch.php and manualDataUpdate.php show Hardware Vendor after each lookup through the existing ExampleUtils::getEnterpriseValue, which reads it only when the data file has it and otherwise says "needs the Enterprise data file". On the Lite file each then prints the existing note, "Some of these properties need the Enterprise data file. Contact us for a copy at" and the tagged contact page, once. manualDataUpdate.php, whose purpose is updating the data file, also says that the Enterprise data file adds daily automatic updates, the wording the on-premise web page already uses.

The match metrics link (DX-php-20). classes/MatchMetrics.php prints https://51degrees.com/documentation/_device_detection__hash.html tagged as above, followed by #DeviceDetection_Hash_DataSetProduction, and the two links in the doc comment of matchMetrics.php are full tagged addresses. Both pages answer and the page holds that anchor.

The readme (DX-php-30). device-detection/onpremise/readme.md says to run composer install in device-detection/onpremise, because the examples load that package's vendor/autoload.php and the root install does not create it, and then, from the same folder, php -S localhost:3000 examples/onpremise/gettingStartedWeb.php or php examples/onpremise/gettingStartedConsole.php.

AGENTS.md (DX-php-39). "Correct output" gives the Enterprise lines and the note for both getting started examples, says the IP Intelligence lines read "needs the Enterprise data file", and describes the Find out more section and its tags. "What CI does not test" is now "What CI tests", naming the tests that run the example scripts in their own PHP, what each checks, and when they do not run (no TAC file, no resource key for location, no on-premise build on Windows or PHP 7.4).

Not changed. Exit statuses are as they were, so the Device Detection and IP Intelligence cloud console examples given no key still exit with status 1 and the location ones with 0, because how a cloud example ends without a key is an open rule question for James. The Device Detection on-premise data file download and hash-php.i are untouched. No package code under any src folder changed.

How it was tested

The tests. Each test runs an example in its own PHP, as someone runs it from a fresh clone, through a small helper in each package's tests, tests/classes/ExampleRun.php (tests/ExampleRun.php in 51Did). The helper starts PHP with proc_open, leaves out the environment variables it is given (the resource key names for a cloud example, and the data file names for the Device Detection on-premise examples and the IP Intelligence on-premise web pages), and for a web page sets the request variables PHP from the command line puts in $_SERVER, a GET for /. Its checks are that the console output ends with the heading followed only by label: address lines, or that a page shows nothing after the section's list, and that every link to 51degrees.com, www.51degrees.com or configure.51degrees.com printed to either stream carries utm_source=code&utm_medium=example&utm_campaign=51degrees-php, a utm_content starting examples- and a utm_term of at most 60 characters, in that order. Two kinds of link pass as they are, being a package's own message (utm_medium=comment with a utm_content starting src-) and the engine's own message, which carries its own repository's campaign, such as the no-value reason from the Device Detection engine that failureToMatch.php prints (utm_campaign=51degrees-cxx). The exit status of a cloud example with no key is not checked.

Red. Run 43537387948 on tmp/fixer-ex-red 9618922, which is rc 6d95eee with the tests (3eb1df2) and a throwaway workflow, on Ubuntu with PHP 8.0, 8.3 and 8.5, Windows with PHP 8.3 and Ubuntu with PHP 7.4. Every new check failed, for the reasons the fix addresses:

  • Device Detection on-premise "Tests: 7, Assertions: 35, Failures: 6", each "No Find out more section". testGettingStartedWeb passed, because that page already had the section, which now comes from the helper.
  • IP Intelligence on-premise "Tests: 10, Assertions: 37, Failures: 8, Skipped: 1", each "No Find out more section" (the skip is testMixed, which needs the Device Detection extension as well).
  • IP Intelligence cloud with no key "Tests: 6, Assertions: 17, Failures: 6", each message naming resource_key rather than _51DEGREES_RESOURCE_KEY.
  • Device Detection cloud with no key "Tests: 8, Assertions: 25, Failures: 8", location "Tests: 5, Assertions: 14, Failures: 5", pipeline core "Tests: 4, Assertions: 8, Failures: 2" and 51Did "Tests: 2, Assertions: 6, Failures: 2". The location index.php stopped with "PHP Fatal error: Uncaught Error: Using $this when not in object context in .../location/examples/index.php:42", and the 51Did server printed only "Set _51DEGREES_RESOURCE_KEY to the resource key of the page."

Green. Run 43537387550 on tmp/fixer-ex-green e7d7fba, which is ceba24c, this draft's change before rc was merged in, with the same workflow, passed in all six jobs. On each of PHP 8.0, 8.3 and 8.5 on Ubuntu, Device Detection on-premise "OK (7 tests, 112 assertions)", IP Intelligence on-premise "Tests: 10, Assertions: 158, Skipped: 1.", IP Intelligence cloud "OK (6 tests, 102 assertions)", Device Detection cloud "OK (8 tests, 119 assertions)", location "OK (5 tests, 71 assertions)" and pipeline core "OK (4 tests, 19 assertions)", with 51Did, which needs PHP 8.1, "OK (2 tests, 19 assertions)" on 8.3 and 8.5. The Windows PHP 8.3 job gave the same for Device Detection cloud, location, pipeline core and 51Did, and the Ubuntu PHP 7.4 job the same for Device Detection cloud, location and pipeline core. Its readme job followed the new device-detection/onpremise/readme.md from a checkout, building the extension and naming the Lite file in php.ini as the readme says, then composer install in device-detection/onpremise from Packagist, php examples/onpremise/gettingStartedConsole.php, which ended with Find out more, and php -S localhost:3001 examples/onpremise/gettingStartedWeb.php, which answered HTTP 200 with the section. The command the readme gave before, from the examples folder, answered HTTP 500.

The rc merge. rc at 70424ea5, which now holds #88 and #89, is merged in with a merge commit, 813e23a, with no conflicts. Its tree is the one git merge-tree gives for ceba24c and 70424ea, so nothing was edited in the merge. The links into files above are at ceba24c, the commit that made the change.

Full build. Run 43554832737 on tmp/pr-matrix-98-c, common-ci's pull request build of this draft from rc 70424ea with merging turned off, passed in all eight legs, Ubuntu with PHP 7.4, 8.0, 8.1, 8.2, 8.3, 8.4 and 8.5 and Windows with PHP 8.3. All nine "Setting 'PullRequestSha'" lines name this head, 813e23a, and Configure printed "Left out 5 macOS entries". On Ubuntu with PHP 8.3 the Device Detection on-premise unit suite gave "OK (72 tests, 312 assertions)", the IP Intelligence unit suite "OK (42 tests, 203 assertions)" and its integration suite, which now holds #88's MixedExamplesTests, "OK (71 tests, 944 assertions)", the Device Detection cloud unit suite "OK (29 tests, 203 assertions)", location "OK (16 tests, 124 assertions)", pipeline core "Tests: 509, Assertions: 4205, Skipped: 1.", 51Did "OK (192 tests, 2641 assertions)" and #89's derived property suite "OK (52 tests, 140 assertions)". Run 43552264429 built ceba24c the same way, from rc 6d95eee, and passed too.

macOS was left out of this draft's full build under the 9 November decision. The rc head is built with macOS before it merges into main.

The draft's own checks are green on this head (link lint, environment variable names and only rc into main).

What remains

  1. The two mixed on-premise examples. Load both on-premise extensions in one PHP, and run the mixed examples on the free data files #88 is now on rc and merged in here. Its MixedExamplesTests checks the two mixed examples with both extensions loaded but not their Find out more section, and here onpremise/web-mixed/index.php is rendered only with the Device Detection extension missing. #101 adds that check to MixedExamplesTests.
  2. Exit statuses. A cloud example given no key exits as before. Whether it should exit with status 0, so that CI can run it with no settings like the on-premise examples, is an open rule question for James, and the tests here do not check the status so that the answer needs no test change.
  3. With a key. The section at the end of a cloud console example run with a key is the same helper call the no-key runs check, and no test here runs those examples with a key. The Device Detection cloud web page is checked with a key in ExampleWebTests.php.
  4. Other drafts. The on-premise Device Detection data file download and the extension starting with no data file (DX-php-26 and DX-php-29) are in #91, which changes the start of the same on-premise examples and one line of device-detection/onpremise/readme.md that this draft also changes. Start PHP with no Device Detection data file, and run the on-premise examples with nothing set #91 merges after this draft and takes rc then. hash-php.i is not touched here.
  5. Found and left alone, now in #101. The doc comments of both Device Detection gettingStartedWeb.php examples still link the JavaScriptBuilderElement reference with a relative /documentation/4.5/apis/... address, which is not printed. The 51Did creator context server's comment says to run composer install at the repository root, while the server loads pipeline/did/vendor/autoload.php, which that install does not create.
  6. Throwaway branches. tmp/fixer-ex-red, tmp/fixer-ex-green, tmp/pr-matrix-98, tmp/pr-matrix-98-b and tmp/pr-matrix-98-c are deleted now that this description cites their runs.

Each package's tests run its examples in their own PHP, as someone runs
them from a fresh clone: the on-premise examples with php.ini naming a
free data file, and the cloud examples with no resource key. Each run must
end with the Find out more section, and every 51degrees.com link it prints
must carry utm_source=code, utm_medium=example, utm_campaign=51degrees-php,
the example's file as utm_content and a utm_term. The Device Detection
on-premise failure to match and manual data update examples must show an
Enterprise only property as needing the Enterprise data file with the
contact link, the match metrics example must print a full documentation
address, and the cloud examples must give a configuration page link when
no key is set.
Each package with an ExampleUtils or Constants class gets one helper that
writes the Find out more section, as text for a console example and as a
list for a web page, with the repositories as bare addresses and the
51degrees.com pages tagged utm_source=code, utm_medium=example,
utm_campaign=51degrees-php, the example's file as utm_content and a
utm_term. Every console example and web page ends with it, including an
early end such as a cloud example run with no resource key. The pipeline
core and 51Did examples, which have no such class, write their own.

The IP Intelligence cloud examples now tag their configuration page link
utm_source=code and name _51DEGREES_RESOURCE_KEY, the mixed console
example and the 51Did creator context server give the configuration page
link, and the two IP Intelligence cloud web pages link it too. The location
index page says what the key is for instead of stopping with a fatal error.
The Device Detection on-premise failure to match and manual data update
examples show HardwareVendor, as needing the Enterprise data file on the
Lite file, with the contact link. The match metrics example prints a full
documentation address rather than a relative one.

The readmes, the IP Intelligence CI notes and AGENTS.md name
_51DEGREES_RESOURCE_KEY, the Device Detection on-premise readme gives a
start command that works from a fresh clone, and AGENTS.md describes the
examples' output and what CI runs as they are now. The examples still read
resource_key when _51DEGREES_RESOURCE_KEY is not set, and exit statuses are
unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant