1: <?php
  2: 
  3: namespace SellerLabs\Snagshout;
  4: 
  5: use Closure;
  6: use DateTime;
  7: use GuzzleHttp\Client as HttpClient;
  8: use Http\Adapter\Guzzle6\Client as GuzzleAdapter;
  9: use GuzzleHttp\Handler\CurlHandler;
 10: use GuzzleHttp\HandlerStack;
 11: use GuzzleHttp\Psr7\Uri;
 12: use Http\Message\MessageFactory\GuzzleMessageFactory;
 13: use Joli\Jane\Runtime\Encoder\RawEncoder;
 14: use Psr\Http\Message\RequestInterface;
 15: use SellerLabs\Snagshout\Resource\CampaignResource;
 16: use SellerLabs\Snagshout\Resource\CategoryResource;
 17: use SellerLabs\Snagshout\Resource\FrontResource;
 18: use SellerLabs\Snagshout\Utils\NormalizerFactory;
 19: use SellerLabs\Snagshout\Resource\DefaultResource;
 20: use Symfony\Component\Serializer\Encoder\JsonDecode;
 21: use Symfony\Component\Serializer\Encoder\JsonEncode;
 22: use Symfony\Component\Serializer\Encoder\JsonEncoder;
 23: use Symfony\Component\Serializer\Serializer;
 24: 
 25:  26:  27:  28:  29:  30:  31: 
 32: class Client
 33: {
 34:      35:  36: 
 37:     protected $publicId;
 38: 
 39:      40:  41: 
 42:     protected $secretKey;
 43: 
 44:      45:  46: 
 47:     protected $endpoint;
 48: 
 49:      50:  51:  52:  53:  54: 
 55:     public function __construct($publicId, $secretKey)
 56:     {
 57:         $this->publicId = $publicId;
 58:         $this->secretKey = $secretKey;
 59: 
 60:         $this->endpoint = new Uri('https://www.snagshout.com');
 61: 
 62:         $stack = new HandlerStack();
 63: 
 64:         $stack->setHandler(new CurlHandler());
 65: 
 66:         $stack->push($this->makeAuthHandler());
 67: 
 68:         $this->client = new HttpClient([
 69:             'handler' => $stack,
 70:         ]);
 71:     }
 72: 
 73:      74:  75: 
 76:     public function setPublicId(string $publicId)
 77:     {
 78:         $this->publicId = $publicId;
 79:     }
 80: 
 81:      82:  83: 
 84:     public function setSecretKey(string $secretKey)
 85:     {
 86:         $this->secretKey = $secretKey;
 87:     }
 88: 
 89:      90:  91: 
 92:     public function setEndpoint(Uri $endpoint)
 93:     {
 94:         $this->endpoint = $endpoint;
 95:     }
 96: 
 97:      98:  99: 100: 101: 102: 103: 
104:     protected function hash($content)
105:     {
106:         $timestamp = (new DateTime())->format('Y-m-d H');
107: 
108:         return hash_hmac(
109:             'sha512',
110:             $content . $timestamp,
111:             $this->secretKey
112:         );
113:     }
114: 
115:     116: 117: 118: 119: 120: 
121:     protected function makeAuthHandler()
122:     {
123:         return function (callable $handler) {
124:             return function (
125:                 RequestInterface $request,
126:                 array $options
127:             ) use ($handler) {
128:                 $contentHash = $this->hash($request->getBody());
129: 
130:                 $partialUri = $request->getUri();
131:                 $uri = $this->endpoint
132:                     ->withPath(
133:                         $this->endpoint->getPath()
134:                         . $partialUri->getPath()
135:                     )
136:                     ->withQuery($partialUri->getQuery())
137:                     ->withFragment($partialUri->getFragment());
138: 
139:                 $request = $request
140:                     ->withUri($uri)
141:                     ->withHeader(
142:                         'Authorization',
143:                         vsprintf('Hash %s', [$this->publicId])
144:                     )
145:                     ->withHeader('Content-Hash', $contentHash);
146: 
147:                 return $handler($request, $options);
148:             };
149:         };
150:     }
151: 
152:     153: 154: 155: 156: 157: 158: 
159:     protected function buildResource($resourceClass)
160:     {
161:         return new $resourceClass(
162:             new GuzzleAdapter($this->client),
163:             new GuzzleMessageFactory(),
164:             new Serializer(
165:                 NormalizerFactory::create(),
166:                 [
167:                     new JsonEncoder(
168:                         new JsonEncode(),
169:                         new JsonDecode()
170:                     ),
171:                     new RawEncoder()
172:                 ]
173:             )
174:         );
175:     }
176: 
177:     178: 179: 180: 181: 
182:     public function campaign()
183:     {
184:         return $this->buildResource(CampaignResource::class);
185:     }
186: 
187:     188: 189: 190: 191: 
192:     public function category()
193:     {
194:         return $this->buildResource(CategoryResource::class);
195:     }
196: 
197:     198: 199: 200: 201: 
202:     public function front()
203:     {
204:         return $this->buildResource(FrontResource::class);
205:     }
206: }