client = $client; $this->state = $state; $this->source = $source; $this->options = $options; $this->init(); $this->partSize = $this->calculatePartSize(); } /** * {@inheritdoc} */ public static function getAllEvents() { return array( self::BEFORE_PART_UPLOAD, self::AFTER_UPLOAD, self::BEFORE_PART_UPLOAD, self::AFTER_PART_UPLOAD, self::AFTER_ABORT, self::AFTER_COMPLETE ); } /** * {@inheritdoc} */ public function abort() { $command = $this->getAbortCommand(); $result = $command->getResult(); $this->state->setAborted(true); $this->stop(); $this->dispatch(self::AFTER_ABORT, $this->getEventData($command)); return $result; } /** * {@inheritdoc} */ public function stop() { $this->stopped = true; return $this->state; } /** * {@inheritdoc} */ public function getState() { return $this->state; } /** * Get the array of options associated with the transfer * * @return array */ public function getOptions() { return $this->options; } /** * {@inheritdoc} * @throws MultipartUploadException when an error is encountered. Use getLastException() to get more information. * @throws RuntimeException when attempting to upload an aborted transfer */ public function upload() { if ($this->state->isAborted()) { throw new RuntimeException('The transfer has been aborted and cannot be uploaded'); } $this->stopped = false; $eventData = $this->getEventData(); $this->dispatch(self::BEFORE_UPLOAD, $eventData); try { $this->transfer(); $this->dispatch(self::AFTER_UPLOAD, $eventData); if ($this->stopped) { return null; } else { $result = $this->complete(); $this->dispatch(self::AFTER_COMPLETE, $eventData); } } catch (\Exception $e) { throw new MultipartUploadException($this->state, $e); } return $result; } /** * Get an array used for event notifications * * @param OperationCommand $command Command to include in event data * * @return array */ protected function getEventData(OperationCommand $command = null) { $data = array( 'transfer' => $this, 'source' => $this->source, 'options' => $this->options, 'client' => $this->client, 'part_size' => $this->partSize, 'state' => $this->state ); if ($command) { $data['command'] = $command; } return $data; } /** * Hook to initialize the transfer */ protected function init() {} /** * Determine the upload part size based on the size of the source data and * taking into account the acceptable minimum and maximum part sizes. * * @return int The part size */ abstract protected function calculatePartSize(); /** * Complete the multipart upload * * @return Model Returns the result of the complete multipart upload command */ abstract protected function complete(); /** * Hook to implement in subclasses to perform the actual transfer */ abstract protected function transfer(); /** * Fetches the abort command fom the concrete implementation * * @return OperationCommand */ abstract protected function getAbortCommand(); }