mirror of
https://github.com/shlinkio/shlink.git
synced 2024-11-23 05:13:13 +03:00
Created VisitsTracker service to track visits to shortcodes
This commit is contained in:
parent
b2615d0de6
commit
4ae08c02ec
4 changed files with 127 additions and 71 deletions
|
@ -2,7 +2,7 @@
|
|||
use Acelaya\UrlShortener\Factory\CacheFactory;
|
||||
use Acelaya\UrlShortener\Factory\EntityManagerFactory;
|
||||
use Acelaya\UrlShortener\Middleware;
|
||||
use Acelaya\UrlShortener\Service\UrlShortener;
|
||||
use Acelaya\UrlShortener\Service;
|
||||
use Acelaya\ZsmAnnotatedServices\Factory\V3\AnnotatedFactory;
|
||||
use Doctrine\Common\Cache\Cache;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
|
@ -34,7 +34,8 @@ return [
|
|||
// Services
|
||||
EntityManager::class => EntityManagerFactory::class,
|
||||
GuzzleHttp\Client::class => InvokableFactory::class,
|
||||
UrlShortener::class => AnnotatedFactory::class,
|
||||
Service\UrlShortener::class => AnnotatedFactory::class,
|
||||
Service\VisitsTracker::class => AnnotatedFactory::class,
|
||||
Cache::class => CacheFactory::class,
|
||||
|
||||
// Middleware
|
||||
|
|
|
@ -15,7 +15,7 @@ class Visit extends AbstractEntity
|
|||
{
|
||||
/**
|
||||
* @var string
|
||||
* @ORM\Column(type="string", length=256)
|
||||
* @ORM\Column(type="string", length=256, nullable=true)
|
||||
*/
|
||||
protected $referer;
|
||||
/**
|
||||
|
@ -25,19 +25,14 @@ class Visit extends AbstractEntity
|
|||
protected $date;
|
||||
/**
|
||||
* @var string
|
||||
* @ORM\Column(type="string", length=256)
|
||||
* @ORM\Column(type="string", length=256, name="remote_addr", nullable=true)
|
||||
*/
|
||||
protected $country;
|
||||
protected $remoteAddr;
|
||||
/**
|
||||
* @var string
|
||||
* @ORM\Column(type="string", length=256)
|
||||
* @ORM\Column(type="string", length=256, name="user_agent", nullable=true)
|
||||
*/
|
||||
protected $platform;
|
||||
/**
|
||||
* @var string
|
||||
* @ORM\Column(type="string", length=256)
|
||||
*/
|
||||
protected $browser;
|
||||
protected $userAgent;
|
||||
/**
|
||||
* @var ShortUrl
|
||||
* @ORM\ManyToOne(targetEntity=ShortUrl::class)
|
||||
|
@ -45,6 +40,11 @@ class Visit extends AbstractEntity
|
|||
*/
|
||||
protected $shortUrl;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->date = new \DateTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
|
@ -81,60 +81,6 @@ class Visit extends AbstractEntity
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCountry()
|
||||
{
|
||||
return $this->country;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $country
|
||||
* @return $this
|
||||
*/
|
||||
public function setCountry($country)
|
||||
{
|
||||
$this->country = $country;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPlatform()
|
||||
{
|
||||
return $this->platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $platform
|
||||
* @return $this
|
||||
*/
|
||||
public function setPlatform($platform)
|
||||
{
|
||||
$this->platform = $platform;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getBrowser()
|
||||
{
|
||||
return $this->browser;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $browser
|
||||
* @return $this
|
||||
*/
|
||||
public function setBrowser($browser)
|
||||
{
|
||||
$this->browser = $browser;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ShortUrl
|
||||
*/
|
||||
|
@ -152,4 +98,40 @@ class Visit extends AbstractEntity
|
|||
$this->shortUrl = $shortUrl;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRemoteAddr()
|
||||
{
|
||||
return $this->remoteAddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $remoteAddr
|
||||
* @return $this
|
||||
*/
|
||||
public function setRemoteAddr($remoteAddr)
|
||||
{
|
||||
$this->remoteAddr = $remoteAddr;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getUserAgent()
|
||||
{
|
||||
return $this->userAgent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $userAgent
|
||||
* @return $this
|
||||
*/
|
||||
public function setUserAgent($userAgent)
|
||||
{
|
||||
$this->userAgent = $userAgent;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ namespace Acelaya\UrlShortener\Middleware\Routable;
|
|||
|
||||
use Acelaya\UrlShortener\Service\UrlShortener;
|
||||
use Acelaya\UrlShortener\Service\UrlShortenerInterface;
|
||||
use Acelaya\UrlShortener\Service\VisitsTracker;
|
||||
use Acelaya\UrlShortener\Service\VisitsTrackerInterface;
|
||||
use Acelaya\ZsmAnnotatedServices\Annotation\Inject;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
|
@ -15,16 +17,22 @@ class RedirectMiddleware implements MiddlewareInterface
|
|||
* @var UrlShortenerInterface
|
||||
*/
|
||||
private $urlShortener;
|
||||
/**
|
||||
* @var VisitsTracker|VisitsTrackerInterface
|
||||
*/
|
||||
private $visitTracker;
|
||||
|
||||
/**
|
||||
* RedirectMiddleware constructor.
|
||||
* @param UrlShortenerInterface|UrlShortener $urlShortener
|
||||
* @param VisitsTrackerInterface|VisitsTracker $visitTracker
|
||||
*
|
||||
* @Inject({UrlShortener::class})
|
||||
* @Inject({UrlShortener::class, VisitsTracker::class})
|
||||
*/
|
||||
public function __construct(UrlShortenerInterface $urlShortener)
|
||||
public function __construct(UrlShortenerInterface $urlShortener, VisitsTrackerInterface $visitTracker)
|
||||
{
|
||||
$this->urlShortener = $urlShortener;
|
||||
$this->visitTracker = $visitTracker;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -55,7 +63,7 @@ class RedirectMiddleware implements MiddlewareInterface
|
|||
public function __invoke(Request $request, Response $response, callable $out = null)
|
||||
{
|
||||
$shortCode = $request->getAttribute('shortCode', '');
|
||||
|
||||
|
||||
try {
|
||||
$longUrl = $this->urlShortener->shortCodeToUrl($shortCode);
|
||||
|
||||
|
@ -65,8 +73,12 @@ class RedirectMiddleware implements MiddlewareInterface
|
|||
return $out($request, $response);
|
||||
}
|
||||
|
||||
// Return a redirect response to the long URL
|
||||
return new RedirectResponse($longUrl, 301);
|
||||
// Track visit to this shortcode
|
||||
$this->visitTracker->track($shortCode);
|
||||
|
||||
// Return a redirect response to the long URL.
|
||||
// Use a temporary redirect to make sure browsers aleways hit the server for analytics purposes
|
||||
return new RedirectResponse($longUrl);
|
||||
} catch (\Exception $e) {
|
||||
// In case of error, dispatch 404 error
|
||||
return $out($request, $response);
|
||||
|
|
61
src/Service/VisitsTracker.php
Normal file
61
src/Service/VisitsTracker.php
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
namespace Acelaya\UrlShortener\Service;
|
||||
|
||||
use Acelaya\UrlShortener\Entity\ShortUrl;
|
||||
use Acelaya\UrlShortener\Entity\Visit;
|
||||
use Acelaya\ZsmAnnotatedServices\Annotation\Inject;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
class VisitsTracker implements VisitsTrackerInterface
|
||||
{
|
||||
/**
|
||||
* @var EntityManagerInterface
|
||||
*/
|
||||
private $em;
|
||||
|
||||
/**
|
||||
* VisitsTracker constructor.
|
||||
* @param EntityManagerInterface $em
|
||||
*
|
||||
* @Inject({"em"})
|
||||
*/
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $em;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks a new visit to provided short code, using an array of data to look up information
|
||||
*
|
||||
* @param string $shortCode
|
||||
* @param array $visitorData Defaults to global $_SERVER
|
||||
*/
|
||||
public function track($shortCode, array $visitorData = null)
|
||||
{
|
||||
$visitorData = $visitorData ?: $_SERVER;
|
||||
|
||||
/** @var ShortUrl $shortUrl */
|
||||
$shortUrl = $this->em->getRepository(ShortUrl::class)->findOneBy([
|
||||
'shortCode' => $shortCode,
|
||||
]);
|
||||
|
||||
$visit = new Visit();
|
||||
$visit->setShortUrl($shortUrl)
|
||||
->setUserAgent($this->getArrayValue($visitorData, 'HTTP_USER_AGENT'))
|
||||
->setReferer($this->getArrayValue($visitorData, 'REFERER'))
|
||||
->setRemoteAddr($this->getArrayValue($visitorData, 'REMOTE_ADDR'));
|
||||
$this->em->persist($visit);
|
||||
$this->em->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $array
|
||||
* @param $key
|
||||
* @param null $default
|
||||
* @return mixed|null
|
||||
*/
|
||||
protected function getArrayValue(array $array, $key, $default = null)
|
||||
{
|
||||
return isset($array[$key]) ? $array[$key] : $default;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue