Created
April 29, 2016 20:03
-
-
Save sameg14/85ccf0332800d115521dd40612495d9a to your computer and use it in GitHub Desktop.
An example service that contains business logic
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Tib\CoreBundle\Service; | |
use Aws\S3\S3Client; | |
use Tib\CoreBundle\Model\User; | |
use Aws\S3\Iterator\ListObjectsIterator; | |
use Tib\CoreBundle\Exception\UploadException; | |
use Aws\Common\Credentials\CredentialsInterface; | |
use Tib\CoreBundle\Exception\InvalidDataException; | |
use Tib\CoreBundle\Exception\MissingDataException; | |
use Symfony\Component\HttpFoundation\Session\Session; | |
use Tib\CoreBundle\Exception\InvalidCredentialsException; | |
/** | |
* Class S3Service handles all interactions with S3 for mixes and images | |
* | |
* @package Tib\CoreBundle\Service | |
*/ | |
class S3Service extends AbstractService | |
{ | |
const BASE_MIX_BUCKET = 'theillbeat/mixes/'; | |
const BASE_IMAGE_BUCKET = 'theillbeat/images/mixes/'; | |
/** | |
* @var S3Client | |
*/ | |
protected $client; | |
/** | |
* Hydrated AWS credentials object | |
* @var CredentialsInterface | |
*/ | |
protected $credentials; | |
public function __construct(CredentialsInterface $credentials, Session $session, $rootDirectory) | |
{ | |
$this->credentials = $credentials; | |
$this->client = S3Client::factory(['credentials' => $credentials]); | |
$this->setSession($session); | |
$this->setRootDir($rootDirectory); | |
} | |
/** | |
* Ensure that the user image and mix buckets exist | |
* | |
* @param string $username SEF username | |
* | |
* @return bool | |
*/ | |
public function ensureUserBuckets($username) | |
{ | |
$didCreateMix = $didCreateImage = false; | |
$userMixBucket = self::BASE_MIX_BUCKET . $username . '/'; | |
$userImageBucket = self::BASE_IMAGE_BUCKET . $username . '/'; | |
// User's mix bucket | |
if (!$this->ensureBucket($userMixBucket)) { | |
$didCreateMix = $this->createBucket($userMixBucket); | |
} | |
// User's image bucket | |
if (!$this->ensureBucket($userImageBucket)) { | |
$didCreateImage = $this->createBucket($userImageBucket); | |
} | |
return $didCreateMix && $didCreateImage; | |
} | |
/** | |
* Upload a mix to S3 | |
* | |
* @param string $usernameSlug Username of this user | |
* @param string $mixSlug Slug for this mix | |
* @param string $mixAbsPath Where is the file located on the current server | |
* | |
* @throws InvalidDataException | |
* @throws UploadException | |
* @throws MissingDataException | |
* @return string Publicly accessible URL for the mix | |
*/ | |
public function uploadMix($usernameSlug, $mixSlug, $mixAbsPath) | |
{ | |
if (empty($mixAbsPath)) { | |
throw new InvalidDataException('Absolute path of mix cannot be empty'); | |
} | |
if (empty($usernameSlug)) { | |
throw new InvalidDataException('Username slug cannot be empty'); | |
} | |
if (empty($mixSlug)) { | |
throw new InvalidDataException('Mix slug cannot be empty'); | |
} | |
// if (!file_exists($mixAbsPath)) { | |
// throw new MissingDataException('Cannot locate mix locally'); | |
// } | |
$mixName = $mixSlug . '.mp3'; | |
$streamPutObject = $this->getClient()->putObject( | |
array( | |
'Bucket' => S3Service::BASE_MIX_BUCKET . $usernameSlug, | |
'Key' => $mixName, | |
'Body' => fopen($mixAbsPath, 'r+'), | |
'ACL' => 'public-read' | |
) | |
); | |
if (!$streamPutObject) { | |
throw new UploadException('Cannot upload mix to the cloud'); | |
} | |
$data = $streamPutObject->toArray(); | |
if (!$data) { | |
throw new UploadException('Invalid data received after uploading to S3'); | |
} | |
if (!array_key_exists('ObjectURL', $data)) { | |
throw new UploadException('Could not get newly saved mix URL'); | |
} | |
unlink($mixAbsPath); | |
return $data['ObjectURL']; | |
} | |
/** | |
* Upload mix images to S3 | |
* | |
* @param string $usernameSlug Username slug of this person | |
* @param string $largeRelPath Large image relative location on this server | |
* @param string $thumbRelPath Thumb image relative location on this server | |
* @param string $imageAbsPath Absolute location for the big images folder on the server | |
* @param string $thumbAbsPath Absolute location for the thumbnail images folder on the server | |
* | |
* @throws InvalidDataException | |
* @throws MissingDataException | |
* @throws UploadException | |
* @return array containing URLS of both images array('large' => 's3/img.jpg', 'thumb' => 's3/tn_img.jpg') | |
*/ | |
public function uploadMixImages($usernameSlug, $largeRelPath, $thumbRelPath, $imageAbsPath = null, $thumbAbsPath = null) | |
{ | |
if (empty($usernameSlug)) { | |
throw new MissingDataException('Login again, your session may have expired'); | |
} | |
if (empty($largeRelPath)) { | |
throw new MissingDataException('No large image found'); | |
} | |
if (empty($thumbRelPath)) { | |
throw new MissingDataException('No thumbnail found'); | |
} | |
$largeRelName = basename($largeRelPath); | |
$thumbRelName = basename($thumbRelPath); | |
if (empty($imageAbsPath)) { | |
$imageAbsPath = $this->rootDir . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'mixes' . DIRECTORY_SEPARATOR; | |
} | |
$largeBodyPath = $imageAbsPath . $largeRelPath; | |
$largeBodyPath = str_replace('//', '/', $largeBodyPath); | |
if (!file_exists($largeBodyPath)) { | |
return false; | |
} | |
$largeStreamPutObject = $this->getClient()->putObject( | |
array( | |
'Bucket' => S3Service::BASE_IMAGE_BUCKET . $usernameSlug, | |
'Key' => $largeRelName, | |
'Body' => fopen($largeBodyPath, 'r+'), | |
'ACL' => 'public-read' | |
) | |
); | |
$largeData = $largeStreamPutObject->toArray(); | |
if (empty($thumbAbsPath)) { | |
$thumbAbsPath = $this->rootDir . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'thumbs' . DIRECTORY_SEPARATOR; | |
} | |
$thumbBodyPath = $thumbAbsPath . DIRECTORY_SEPARATOR . $thumbRelPath; | |
$thumbBodyPath = str_replace('//', '/', $thumbBodyPath); | |
if (!file_exists($thumbBodyPath)) { | |
return false; | |
} | |
$thumbStreamPutObject = $this->getClient()->putObject( | |
array( | |
'Bucket' => S3Service::BASE_IMAGE_BUCKET . $usernameSlug, | |
'Key' => $thumbRelName, | |
'Body' => fopen($thumbBodyPath, 'r+'), | |
'ACL' => 'public-read' | |
) | |
); | |
$thumbData = $thumbStreamPutObject->toArray(); | |
if (!empty($largeData) && !empty($thumbData)) { | |
return array( | |
'large' => $largeData['ObjectURL'], | |
'thumb' => $thumbData['ObjectURL'], | |
'largeLocalAbs' => $largeBodyPath, | |
'thumbLocalAbs' => $thumbBodyPath | |
); | |
} | |
throw new UploadException('An unknown error occurred when trying to upload mix images to S3'); | |
} | |
/** | |
* Remove a mix from S3 | |
* | |
* @param string $usernameSlug Slug for this user's username | |
* @param string $mixSlug Slug for this mix, with no extension | |
* | |
* @throws InvalidDataException | |
* @return bool | |
*/ | |
public function removeMix($usernameSlug, $mixSlug) | |
{ | |
if (empty($usernameSlug)) { | |
throw new InvalidDataException('Username slug cannot be empty'); | |
} | |
if (empty($mixSlug)) { | |
throw new InvalidDataException('Mix slug cannot be empty'); | |
} | |
$mixName = $mixSlug . '.mp3'; | |
$didRemove = $this->getClient()->deleteObject( | |
array( | |
'Bucket' => self::BASE_MIX_BUCKET . $usernameSlug, | |
'Key' => $mixName | |
) | |
); | |
return (bool)$didRemove; | |
} | |
/** | |
* Remove all user buckets | |
* @param string $usernameSlug | |
* @throws InvalidDataException | |
* @return bool | |
*/ | |
public function removeAllUserBuckets($usernameSlug) | |
{ | |
if (empty($usernameSlug)) { | |
throw new InvalidDataException('Username slug cannot be empty'); | |
} | |
$didRemoveMix = $this->getClient()->deleteBucket( | |
array( | |
'Bucket' => self::BASE_MIX_BUCKET . $usernameSlug | |
) | |
); | |
$didRemoveImage = $this->getClient()->deleteBucket( | |
array( | |
'Bucket' => self::BASE_IMAGE_BUCKET . $usernameSlug | |
) | |
); | |
return (bool)$didRemoveMix && (bool)$didRemoveImage; | |
} | |
/** | |
* Ensure that a mix exists on S3 | |
* | |
* @param string $usernameSlug just the username slug | |
* @param string $mixFileName Just the mix filename, with extension | |
* | |
* @return bool | |
*/ | |
public function ensureMix($usernameSlug, $mixFileName) | |
{ | |
return $this->getClient()->doesObjectExist(self::BASE_MIX_BUCKET . $usernameSlug, $mixFileName); | |
} | |
/** | |
* Delete a mix from this user's bucket | |
* @param string $usernameSlug Slug for this user | |
* @param string $mixFileName With extension | |
* @return bool | |
*/ | |
public function deleteMix($usernameSlug, $mixFileName) | |
{ | |
$result = $this->getClient()->deleteObject( | |
array( | |
'Bucket' => self::BASE_MIX_BUCKET . $usernameSlug, | |
'Key' => $mixFileName | |
) | |
); | |
$resultArray = $result->toArray(); | |
return isset($resultArray['DeleteMarker']) && !empty($resultArray['RequestId']) ? true : false; | |
} | |
/** | |
* @param string $usernameSlug Slug for this user | |
* @param string $imageFilename main image | |
* @param string $thumbFilename thumb | |
* @return bool | |
*/ | |
public function deleteMixImages($usernameSlug, $imageFilename, $thumbFilename) | |
{ | |
$imageResult = $this->getClient()->deleteObject( | |
array( | |
'Bucket' => self::BASE_IMAGE_BUCKET . $usernameSlug, | |
'Key' => $imageFilename | |
) | |
); | |
$imageResultArray = $imageResult->toArray(); | |
$didImageDelete = isset($imageResultArray['DeleteMarker']) && !empty($imageResultArray['RequestId']) ? true : false; | |
$thumbResult = $this->getClient()->deleteObject( | |
array( | |
'Bucket' => self::BASE_IMAGE_BUCKET . $usernameSlug, | |
'Key' => $thumbFilename | |
) | |
); | |
$thumbResultArray = $thumbResult->toArray(); | |
$didThumbDelete = isset($thumbResultArray['DeleteMarker']) && !empty($thumbResultArray['RequestId']) ? true : false; | |
return $didImageDelete && $didThumbDelete; | |
} | |
/** | |
* Ensure that this bucket exists | |
* | |
* @param string $bucket Absolute path of bucket | |
* | |
* @return bool | |
*/ | |
public function ensureBucket($bucket) | |
{ | |
return (bool)$this->client->doesBucketExist($bucket); | |
} | |
/** | |
* Get all mixes from this user's bucket | |
* | |
* @param string $usernameSlug just the username slug | |
* | |
* @return ListObjectsIterator|null | |
*/ | |
public function getMixes($usernameSlug) | |
{ | |
return $this->getClient()->getIterator('ListObjects', array( | |
'Bucket' => 'theillbeat/', | |
"Prefix" => 'mixes/' . $usernameSlug . '/' | |
)); | |
} | |
/** | |
* Get all mixes from this user's bucket | |
* | |
* @param string $usernameSlug just the username slug | |
* @param string $mixFileName Just the mix filename, with extension | |
* | |
* @return ListObjectsIterator|null | |
*/ | |
public function getMix($usernameSlug, $mixFileName) | |
{ | |
$mixes = $this->getMixes($usernameSlug); | |
$key = 'mixes/' . $usernameSlug . '/' . $mixFileName; | |
foreach ($mixes as $mix) { | |
if ($mix['Key'] == $key) { | |
return $mix; | |
} | |
} | |
return null; | |
} | |
/** | |
* Create a new bucket | |
* | |
* @param string $bucket Full folder path of the bucket from the root ending in a slash | |
* | |
* @return bool | |
*/ | |
public function createBucket($bucket) | |
{ | |
return (bool)$this->client->createBucket( | |
array( | |
'Bucket' => $bucket | |
) | |
); | |
} | |
/** | |
* Get the client ( test and dev only ) | |
* | |
* @return S3Client | |
*/ | |
public function getClient() | |
{ | |
return $this->client; | |
} | |
/** | |
* @param S3Client $s3Client | |
*/ | |
public function setS3Client($s3Client) | |
{ | |
$this->client = $s3Client; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment