# Visitor Info

The `VisitorInfo` is the central data object which is passed to every part of the targeting system. A new `VisitorInfo`
is created for every request and enriched with data throughout the matching process. Starting from an empty object, data
will be added to the `VisitorInfo` from several components, making it hold all relevant targeting data for the current
request.

## Visitor ID

To identify returning visitors, the engine needs some kind of unique identificator which will be assigned to each visitor.
This identificator, internally referred to as `visitor ID`, is expected to be generated or set by the browser and to be
stored as a cookie. When creating a `VisitorInfo` the targeting engine tries to load a visitor ID from the `_pc_vis` cookie.
This ID is (by default) generated by the frontend on event:

* when loading a site with targeting enabled and no visitor ID was previously set, a random string is generated

If you want to manually set the visitor ID in your frontend code you can do so with the following call which is exposed
by the targeting JS implementation:

```js
_ptg.api.setVisitorId('my-custom-visitor-id');
```

The visitor ID will be used for every action where a unique identificator is needed, e.g. when identifying returning visitors
or when persisting data for a specific visitor to a targeting storage.

Upon setting a visitor ID, it is stored in 2 places of the user's browser:

* a `_pc_vis` cookie
* a `_ptg.user` local storage entry. This entry contains some persistent data about the user (e.g. an activity log and a list
  of previous visitor IDs) which may be used in later enhancements of the targeting framework. If the visitor ID cookie
  is missing but the local storage entry contains an ID that ID will be used to write a new cookie.


## Accessing the Visitor Info in your code

Similar to the security token in Symfony's security system, you can fetch the current `VisitorInfo` from a `VisitorInfoStorage`.
This storage is defined as service an can simply be injected into your services or used as controller action argument when
your controllers are registered as service. You can just define the `VisitorInfoStorageInterface` as dependency and Symfony
and the service configuration take care of the rest.

As an example, a sample service working with the `VisitorInfo`:

```php
<?php

namespace App\Targeting;

use Pimcore\Targeting\VisitorInfoStorageInterface;

class MyService
{
    /**
     * @var VisitorInfoStorageInterface
     */
    private $visitorInfoStorage;

    public function __construct(VisitorInfoStorageInterface $visitorInfoStorage)
    {
        $this->visitorInfoStorage = $visitorInfoStorage;
    }

    public function getVisitorId()
    {
        // always check if there is a visitor info before trying to fetch it
        if (!$this->visitorInfoStorage->hasVisitorInfo()) {
            return null;
        }

        $visitorInfo = $this->visitorInfoStorage->getVisitorInfo();

        return $visitorInfo->getVisitorId();
    }
}

```

And the matching service definition:

```yaml
services:
    _defaults:
        autowire: true
        autoconfigure: true
        public: false

    # if using autowiring you're already set by just defining your service - the
    # type hint against the VisitorInfoStorageInterface is enough to enable autowiring
    App\Targeting\MyService: ~

    # if you don't use autowiring you need to manually wire your dependency
    App\Targeting\MyService:
        arguments:
            $visitorInfoStorage: '@Pimcore\Targeting\VisitorInfoStorageInterface'
``` 

If your controllers are defined as services, you can make use of argument injection:

```php
<?php

namespace App\Controller;

use Pimcore\Targeting\VisitorInfoStorageInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;

class VisitorInfoController
{
    /**
     * @Route("/visitor-info")
     */
    public function visitorInfoAction(VisitorInfoStorageInterface $visitorInfoStorage)
    {
        $data = [
            'visitorId' => null
        ];

        // always check if there is a visitor info before trying to fetch it
        if ($visitorInfoStorage->hasVisitorInfo()) {
            $visitorInfo = $visitorInfoStorage->getVisitorInfo();

            $data['visitorId'] = $visitorInfo->getVisitorId();
        }

        return new JsonResponse($data);
    }
}
```
