Segments Manager

PHP-specific segments handling

Welcome back! In Chapter 9: EventManager, we explored the SDK's internal communication system. Now let's look at a component that handles visitor categorization for reporting: the SegmentsManager.

The Problem: Categorizing Visitors for Reports

When analyzing A/B test results, you often want to break down the data by visitor characteristics:

  • "How did mobile users respond to variation B?"
  • "Did premium-tier users convert more often?"
  • "What was the conversion rate for visitors from Canada?"

These categorizations are called segments. The SDK needs a way to evaluate which segments a visitor belongs to and include that information in tracking data sent to the Convert dashboard.

What is SegmentsManager? The Sorting Desk

Think of the SegmentsManager as a sorting desk that categorizes incoming mail (visitors) into the right mailboxes (segments). It checks visitor attributes against segment rules and stores the results for use in tracking and reporting.

Its key responsibilities are:

  1. Evaluate Segments: Check which segments a visitor matches based on their attributes.
  2. Store Segment Data: Persist segment assignments in the visitor's data store.
  3. Provide Segments for Tracking: Supply segment information to the ApiManager for inclusion in tracking payloads.

How it's Used

You interact with the SegmentsManager through the Context object:

1. Set Default Segments (for reporting):

Default segments are standard dimensions that appear in Convert reports.

$context = $convert->createContext('user123', ['country' => 'US']);

// Set reporting segments
$context->setDefaultSegments([
    'country' => 'US',
    'browser' => 'chrome',
    'devices' => 'desktop',
    'source' => 'organic',
]);

Only these properties are included in Convert Reports: browser, devices, source, campaign, visitorType, country.

2. Run Custom Segments:

Custom segments use rule-based matching against visitor attributes.

// Evaluate which custom segments match this visitor
$matchedSegments = $context->runCustomSegments(
    ['premium-users', 'high-value'],
    ['plan' => 'enterprise', 'lifetime_value' => 5000]
);

Under the Hood: How Segments Are Evaluated

When you call $context->runCustomSegments():

  1. Context delegates to the SegmentsManager.
  2. SegmentsManager looks up the segment definitions from the DataManager by key.
  3. For each segment, it uses the RuleManager to evaluate the segment's rules against the visitor's attributes.
  4. Matched segments are stored via the DataManager and returned.
sequenceDiagram
    participant Context as Context
    participant SegMgr as SegmentsManager
    participant DataMgr as DataManager
    participant RuleMgr as RuleManager

    Context->>+SegMgr: selectCustomSegments('user123', ['premium-users'], attributes)
    SegMgr->>+DataMgr: Get segment definition for 'premium-users'
    DataMgr-->>-SegMgr: ConfigSegment {rules: {...}}
    SegMgr->>+RuleMgr: isRuleMatched(visitorData, segmentRules)
    RuleMgr-->>-SegMgr: true (match)
    SegMgr->>+DataMgr: Store segment assignment for 'user123'
    DataMgr-->>-SegMgr: Done
    SegMgr-->>-Context: Return VisitorSegments

Code Dive: SegmentsManager Implementation

1. The Constructor

// File: packages/Segments/src/SegmentsManager.php (Simplified)

namespace ConvertSdk;

class SegmentsManager implements SegmentsManagerInterface
{
    public function __construct(
        private Config $config,
        private DataManagerInterface $dataManager,
        private RuleManagerInterface $ruleManager,
        private ?LogManagerInterface $loggerManager = null,
    ) {
        // ... logging ...
    }
}
  • Stores references to the DataManager (for data access and storage) and RuleManager (for rule evaluation).

2. Evaluating Custom Segments (selectCustomSegments)

// File: packages/Segments/src/SegmentsManager.php (Simplified)

// Inside SegmentsManager class:
    public function selectCustomSegments(
        string $visitorId,
        array $segmentKeys,
        ?array $segmentRule = null
    ): VisitorSegments|RuleError|null {
        $matchedSegments = [];

        foreach ($segmentKeys as $key) {
            // Look up the segment definition
            $segment = $this->dataManager->getEntity($key, 'segments');
            if (!$segment) {
                continue;
            }

            // Use RuleManager to evaluate the segment's rules
            $rules = $segmentRule ?? $segment->rules;
            $matched = $this->ruleManager->isRuleMatched(
                $segmentRule ?? [],
                $rules
            );

            if ($matched === true) {
                $matchedSegments[$segment->id] = $segment->key;
            } elseif ($matched instanceof RuleError) {
                return $matched;
            }
        }

        // Store the matched segments
        $segments = new VisitorSegments(customSegments: $matchedSegments);
        $this->putSegments($visitorId, $matchedSegments);

        return $segments;
    }
  • Iterates through each segment key.
  • Looks up the segment definition from the config via DataManager.
  • Uses RuleManager to check if the visitor matches the segment rules.
  • Stores matched segments and returns them.

3. Storing and Retrieving Segments

// Inside SegmentsManager class:
    public function getSegments(string $visitorId): VisitorSegments
    {
        $data = $this->dataManager->getData($visitorId);
        return new VisitorSegments(
            customSegments: $data['segments']['customSegments'] ?? []
        );
    }

    public function putSegments(string $visitorId, ?array $segments): void
    {
        $this->dataManager->putData($visitorId, [
            'segments' => ['customSegments' => $segments],
        ]);
    }
  • Segments are persisted alongside other visitor data (bucketing decisions, etc.) in the data store.
  • If a PSR-16 cache is configured, segments persist across HTTP requests.

Conclusion

The SegmentsManager handles visitor categorization for Convert's reporting system. It evaluates segment rules against visitor attributes and stores the results for inclusion in tracking data.

You've learned:

  1. Why segments are important for analyzing A/B test results.
  2. How to set default reporting segments and evaluate custom segments.
  3. That SegmentsManager uses the RuleManager to evaluate segment rules.
  4. That segment data persists alongside other visitor data in the data store.

Now let's take a closer look at the configuration options and type definitions that underpin the entire SDK.

Ready to explore the final details? Head to Chapter 11: Config / Types!