diff --git a/README.md b/README.md index a3a6f07..b83c557 100644 --- a/README.md +++ b/README.md @@ -10,21 +10,18 @@ require './vendor/autoload.php'; -use Mediapart\Selligent\Configuration; use Mediapart\Selligent\Connection; use Mediapart\Selligent\Transport; use Mediapart\Selligent\Properties; -/* before define your API credentials in config/YOUR_CONFIG.yml*/ -$configFile = file_get_contents( - __DIR__.'/config/individual_default_config.yaml' -); -$cfg = new \Mediapart\Selligent\Configuration(); - /* connect you to your Selligent API server */ $connection = new Connection(); -$client = $connection->open($cfg->loadConfig($configFile)); +$client = $connection->open([ + 'login' => '*****', + 'password' => '*****', + 'wsdl' => 'http://emsecure/individual?wsdl', +]); /* Example : Trigger the TESTGATE campaign to an user. @@ -81,9 +78,16 @@ With the `real` testsuite, you could execute a serie of test who will be applied - soap_login - soap_password -- soap_wsdl +- soap_wsdl_individual +- soap_wsdl_broadcast - selligent_list - selligent_gate +- selligent_folderid +- selligent_maildomainid +- selligent_listid +- selligent_segmentid +- selligent_queueid +- selligent_macategory ## Read More @@ -91,3 +95,4 @@ With the `real` testsuite, you could execute a serie of test who will be applied - Illustrated [Reference](doc/Reference/Readme.md) of all available API endpoints. - Little use case [Example](doc/Example.md) from connection to triggering campaign - You could use PSR3 to [log informations from this library](doc/Logging.md). +- You could [broadcast campaign based on complete HTML](doc/Broadcast.md) from the API. diff --git a/config/broadcast.yml b/config/broadcast.yml new file mode 100644 index 0000000..3024fbf --- /dev/null +++ b/config/broadcast.yml @@ -0,0 +1,7 @@ +login: ~ +password: ~ +namespace: "http://tempuri.org/" +wsdl: ~ +options: + classmap: + CreateCampaignResponse: "Mediapart\\Selligent\\Response\\CreateCampaignResponse" diff --git a/config/broadcast_default_config.yaml b/config/broadcast_default_config.yaml deleted file mode 100644 index 26fde5d..0000000 --- a/config/broadcast_default_config.yaml +++ /dev/null @@ -1,8 +0,0 @@ -selligent: - login: ~ - password: ~ - namespace: "http://tempuri.org/" - wsdl: ~ - options: - classmap: - CreateCampaign: "Mediapart\\Selligent\\CreateCampaign" diff --git a/config/individual.yml b/config/individual.yml new file mode 100644 index 0000000..a47ced5 --- /dev/null +++ b/config/individual.yml @@ -0,0 +1,38 @@ +login: ~ +password: ~ +namespace: "http://tempuri.org/" +wsdl: ~ +list: +options: + classmap: + ArrayOfListInfo: "Mediapart\\Selligent\\ArrayOfListInfo" + ListInfo: "Mediapart\\Selligent\\ListInfo" + Property: "Mediapart\\Selligent\\Property" + ArrayOfProperty: "Mediapart\\Selligent\\Properties" + # System info + GetSystemStatusResponse: "Mediapart\\Selligent\\Response\\GetSystemStatusResponse" + # Manage Lists + GetListsResponse: "Mediapart\\Selligent\\Response\\GetListsResponse" + GetListIDResponse: "Mediapart\\Selligent\\Response\\GetListIDResponse" + # Manage Segments + CreateSegmentResponse: "Mediapart\\Selligent\\Response\\CreateSegmentResponse" + AddToSegmentResponse: "Mediapart\\Selligent\\Response\\AddToSegmentResponse" + GetSegmentsResponse: "Mediapart\\Selligent\\Response\\GetSegmentsResponse" + GetSegmentRecordCountResponse: "Mediapart\\Selligent\\Response\\GetSegmentRecordCountResponse" + # Manage Users + CreateUserResponse: "Mediapart\\Selligent\\Response\\CreateUserResponse" + UpdateUserResponse: "Mediapart\\Selligent\\Response\\UpdateUserResponse" + UpdateUsersResponse: "Mediapart\\Selligent\\Response\\UpdateUsersResponse" + GetUserByIDResponse: "Mediapart\\Selligent\\Response\\GetUserByIDResponse" + RetrieveHashForUserResponse: "Mediapart\\Selligent\\Response\\RetrieveHashForUserResponse" + CountUsersByConstraintResponse: "Mediapart\\Selligent\\Response\\CountUsersByConstraintResponse" + GetUsersByConstraintResponse: "Mediapart\\Selligent\\Response\\GetUsersByConstraintResponse" + GetUserByConstraintResponse: "Mediapart\\Selligent\\Response\\GetUserByConstraintResponse" + CountUsersByFilterResponse: "Mediapart\\Selligent\\Response\\CountUsersByFilterResponse" + GetUsersByFilterResponse: "Mediapart\\Selligent\\Response\\GetUsersByFilterResponse" + GetUserByFilterResponse: "Mediapart\\Selligent\\Response\\GetUserByFilterResponse" + # Manage Campaign + TriggerCampaignResponse: "Mediapart\\Selligent\\Response\\TriggerCampaignResponse" + TriggerCampaignWithResultResponse: "Mediapart\\Selligent\\Response\\TriggerCampaignWithResultResponse" + TriggerCampaignForUserResponse: "Mediapart\\Selligent\\Response\\TriggerCampaignForUserResponse" + TriggerCampaignForUserWithResultResponse: "Mediapart\\Selligent\\Response\\TriggerCampaignForUserWithResultResponse" \ No newline at end of file diff --git a/config/individual_default_config.yaml b/config/individual_default_config.yaml deleted file mode 100644 index 06f3a33..0000000 --- a/config/individual_default_config.yaml +++ /dev/null @@ -1,39 +0,0 @@ -selligent: - login: ~ - password: ~ - namespace: "http://tempuri.org/" - wsdl: ~ - list: - options: - "classmap": - ArrayOfListInfo: "Mediapart\\Selligent\\ArrayOfListInfo" - ListInfo: "Mediapart\\Selligent\\ListInfo" - Property: "Mediapart\\Selligent\\Property" - ArrayOfProperty: "Mediapart\\Selligent\\Properties" - # System info - GetSystemStatusResponse: "Mediapart\\Selligent\\Response\\GetSystemStatusResponse" - # Manage Lists - GetListsResponse: "Mediapart\\Selligent\\Response\\GetListsResponse" - GetListIDResponse: "Mediapart\\Selligent\\Response\\GetListIDResponse" - # Manage Segments - CreateSegmentResponse: "Mediapart\\Selligent\\Response\\CreateSegmentResponse" - AddToSegmentResponse: "Mediapart\\Selligent\\Response\\AddToSegmentResponse" - GetSegmentsResponse: "Mediapart\\Selligent\\Response\\GetSegmentsResponse" - GetSegmentRecordCountResponse: "Mediapart\\Selligent\\Response\\GetSegmentRecordCountResponse" - # Manage Users - CreateUserResponse: "Mediapart\\Selligent\\Response\\CreateUserResponse" - UpdateUserResponse: "Mediapart\\Selligent\\Response\\UpdateUserResponse" - UpdateUsersResponse: "Mediapart\\Selligent\\Response\\UpdateUsersResponse" - GetUserByIDResponse: "Mediapart\\Selligent\\Response\\GetUserByIDResponse" - RetrieveHashForUserResponse: "Mediapart\\Selligent\\Response\\RetrieveHashForUserResponse" - CountUsersByConstraintResponse: "Mediapart\\Selligent\\Response\\CountUsersByConstraintResponse" - GetUsersByConstraintResponse: "Mediapart\\Selligent\\Response\\GetUsersByConstraintResponse" - GetUserByConstraintResponse: "Mediapart\\Selligent\\Response\\GetUserByConstraintResponse" - CountUsersByFilterResponse: "Mediapart\\Selligent\\Response\\CountUsersByFilterResponse" - GetUsersByFilterResponse: "Mediapart\\Selligent\\Response\\GetUsersByFilterResponse" - GetUserByFilterResponse: "Mediapart\\Selligent\\Response\\GetUserByFilterResponse" - # Manage Campaign - TriggerCampaignResponse: "Mediapart\\Selligent\\Response\\TriggerCampaignResponse" - TriggerCampaignWithResultResponse: "Mediapart\\Selligent\\Response\\TriggerCampaignWithResultResponse" - TriggerCampaignForUserResponse: "Mediapart\\Selligent\\Response\\TriggerCampaignForUserResponse" - TriggerCampaignForUserWithResultResponse: "Mediapart\\Selligent\\Response\\TriggerCampaignForUserWithResultResponse" \ No newline at end of file diff --git a/doc/Broadcast.md b/doc/Broadcast.md new file mode 100644 index 0000000..a5fe0e5 --- /dev/null +++ b/doc/Broadcast.md @@ -0,0 +1,45 @@ + +# Broadcast Complete HTML Campaign + +```php +open( + [ + 'login' => '*****', + 'password' => '*****', + 'wsdl' => 'http://emsecure/broadcast?wsdl', + ], + Connection::API_BROADCAST +); + +/* + Create your campaign. + For complete options, see directly the Selligent API reference and + our implementation in /src/Broadcast/ classes. + */ +$campaign = new Campaign(); +$campaign + ->setName('Campaign Test') + ->setState(Campaign::ACTIVE) + ->setStartDate(new DateTime('tomorrow')) + ->setDescription('Some campaign test scheduled for tomorrow.') +; +// ... + +$writer = new XMLWriter(); +$request = new CreateCampaign($writer); +$xml = $request->basedOn($campaign); +$response = $this->client->CreateCampaign(['Xml' => $xml]); + +if ($response==Response::SUCCESSFUL) { + print 'Your campaign has been created'; +} + +``` diff --git a/doc/Example.md b/doc/Example.md index 9232f1a..1dec58d 100644 --- a/doc/Example.md +++ b/doc/Example.md @@ -5,16 +5,15 @@ namespace Mediapart\Selligent; -$configFile = file_get_contents( - __DIR__.'/config/individual_default_config.yaml' -); -$cfg = new \Mediapart\Selligent\Configuration(); - /* Open a connection to Selligent. */ $connection = new Connection(); -$client = $connection->open($cfg->loadConfig($configFile)); +$client = $connection->open([ + 'login' => '*****', + 'password' => '*****', + 'wsdl' => 'http://emsecure/individual?wsdl', +]); /* Output lists infos. diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 3365030..81aa29e 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -6,10 +6,12 @@ ./tests - ./tests/RealTest.php + ./tests/IndividualTest.php + ./tests/BroadcastTest.php - ./tests/RealTest.php + ./tests/IndividualTest.php + ./tests/BroadcastTest.php diff --git a/src/Broadcast/Campaign.php b/src/Broadcast/Campaign.php new file mode 100644 index 0000000..47e5a67 --- /dev/null +++ b/src/Broadcast/Campaign.php @@ -0,0 +1,260 @@ + + * + * For the full license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Mediapart\Selligent\Broadcast; + +/** + * + */ +class Campaign +{ + const TEST = 'Test'; + const ACTIVE = 'Active'; + const HOLD = 'Hold'; + const DESIGN = 'Design'; + + /** + * @var string The name of the journey map. + */ + private $name; + + /** + * @var string Possible values are Test, Active, Hold, Design. By default the value is set to Design. + */ + private $state; + + /** + * @var integer The ID of the folder in which the journey map is created. + */ + private $folderId; + + /** + * @var \DateTimeInterface This is the start date for the journey map. + */ + private $startDate; + + /** + * @var string The description of the journey map as defined in the properties + */ + private $description; + + /** + * @var string The category defined for the journey map, if any. + */ + private $maCategory; + + /** + * @var integer The ID of the product defined for the journey map, if any. + */ + private $productId; + + /** + * @var integer The ID of the marketing pressure plan to which the journey map is linked. + */ + private $clashPlanId; + + /** + * @var Email[] + */ + private $emails; + + /** + * + */ + public function __construct() + { + $this->state = self::DESIGN; + $this->startDate = new \DateTime(); + $this->emails = []; + } + + /** + * @param string $name The name of the journey map. + * @return self + */ + public function setName($name) + { + $this->name = $name; + + return $this; + } + + /** + * @return string The name of the journey map. + */ + public function getName() + { + return $this->name; + } + + /** + * @param string $state Possible values are Test, Active, Hold, Design. By default the value is set to Design. + * @return self + */ + public function setState($state) + { + $possible = array( + self::TEST, + self::ACTIVE, + self::HOLD, + self::DESIGN, + ); + + if (in_array($state, $possible)) { + $this->state = $state; + } else { + throw new \InvalidArgumentException(); + } + + return $this; + } + + /** + * @return string Possible values are Test, Active, Hold, Design. By default the value is set to Design. + */ + public function getState() + { + return $this->state; + } + + /** + * @param integer $id The ID of the folder in which the journey map is created. + * @return self + */ + public function setFolderId($id) + { + $this->folderId = $id; + + return $this; + } + + /** + * @return integer The ID of the folder in which the journey map is created. + */ + public function getFolderId() + { + return $this->folderId; + } + + /** + * @param \DateTimeInterface $date This is the start date for the journey map. + * @return self + */ + public function setStartDate(\DateTimeInterface $date) + { + $this->startDate = $date; + + return $this; + } + + /** + * @return \DateTimeInterface This is the start date for the journey map. + */ + public function getStartDate() + { + return $this->startDate; + } + + /** + * @param string $description The description of the journey map as defined in the properties. + * @return self + */ + public function setDescription($description) + { + $this->description = $description; + + return $this; + } + + /** + * @return string The description of the journey map as defined in the properties. + */ + public function getDescription() + { + return $this->description; + } + + /** + * @param string $maCategory The category defined for the journey map, if any. + * @return self + */ + public function setMaCategory($maCategory) + { + $this->maCategory = $maCategory; + + return $this; + } + + /** + * @return string The category defined for the journey map, if any. + */ + public function getMaCategory() + { + return $this->maCategory; + } + + /** + * @param integer $productId The ID of the product defined for the journey map, if any. + * @return self + */ + public function setProductId($productId) + { + $this->productId = $productId; + + return $this; + } + + /** + * @return integer The ID of the product defined for the journey map, if any. + */ + public function getProductId() + { + return $this->productId; + } + + /** + * @param integer $clashPlanId The ID of the marketing pressure plan to which the journey map is linked. + * @return self + */ + public function setClashPlanId($clashPlanId) + { + $this->clashPlanId = $clashPlanId; + + return $this; + } + + /** + * @return integer The ID of the marketing pressure plan to which the journey map is linked. + */ + public function getClashPlanId() + { + return $this->clashPlanId; + } + + /** + * @param Email $email + * @return self + */ + public function addEmail(Email $email) + { + $this->emails[] = $email; + + return $this; + } + + /** + * @return Email[] + */ + public function getEmails() + { + return $this->emails; + } +} diff --git a/src/Broadcast/Email.php b/src/Broadcast/Email.php new file mode 100644 index 0000000..7da67f5 --- /dev/null +++ b/src/Broadcast/Email.php @@ -0,0 +1,247 @@ + + * + * For the full license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Mediapart\Selligent\Broadcast; + +/** + * + */ +class Email +{ + /** + * @var string The name as defined for the email message properties. + */ + private $name; + + /** + * @var integer The ID of the folder in which the email is stored. + */ + private $folderId; + + /** + * @var integer The Brand used for sending out the email message. + */ + private $mailDomainId; + + /** + * @var boolean This indicates if the list unsubscribe option has been activated for the email message. + */ + private $unsubscribe; + + /** + * @var integer The queue to which the email messages are transferred for broadcast. + */ + private $queueId; + + /** + * @var string + */ + private $tag; + + /** + * @var string The category attributed to the email message. + */ + private $maCategory; + + /** + * @var Target + */ + private $target; + + /** + * @var array + */ + private $content; + + /** + * @param string $name The name as defined for the email message properties. + * @return self + */ + public function setName($name) + { + $this->name = $name; + + return $this; + } + + /** + * @return string The name as defined for the email message properties. + */ + public function getName() + { + return $this->name; + } + + /** + * @param integer $folderId The ID of the folder in which the email is stored + * @return self + */ + public function setFolderId($folderId) + { + $this->folderId = $folderId; + + return $this; + } + + /** + * @return integer The ID of the folder in which the email is stored + */ + public function getFolderId() + { + return $this->folderId; + } + + /** + * @param boolean This indicates if the list unsubscribe option has been activated for the email message. + * @return self + */ + public function listUnsubscribe($unsubscribe = true) + { + $this->unsubscribe = $unsubscribe; + + return $this; + } + + /** + * @return boolean Indicates if the list unsubscribe option has been activated for the email message. + */ + public function canUnsubscribe() + { + return $this->unsubscribe; + } + + /** + * @param integer The queue to which the email messages are transferred for broadcast. + * @return self + */ + public function setQueueId($queueId) + { + $this->queueId = $queueId; + + return $this; + } + + /** + * @return integer The queue to which the email messages are transferred for broadcast. + */ + public function getQueueId() + { + return $this->queueId; + } + + /** + * @param integer The Brand used for sending out the email message. + * @return self + */ + public function setMailDomainId($mailDomainId) + { + $this->mailDomainId = $mailDomainId; + + return $this; + } + + /** + * @return integer The Brand used for sending out the email message. + */ + public function getMailDomainId() + { + return $this->mailDomainId; + } + + /** + * @param string $tag + * @return self + */ + public function setTag($tag) + { + $this->tag = $tag; + + return $this; + } + + /** + * @return string + */ + public function getTag() + { + return $this->tag; + } + + /** + * @param string The category attributed to the email message. + * @return self + */ + public function setMaCategory($maCategory) + { + $this->maCategory = $maCategory; + + return $this; + } + + /** + * @return string + */ + public function getMaCategory() + { + return $this->maCategory; + } + + /** + * @param Target $target + * @return self + */ + public function setTarget($target) + { + $this->target = $target; + + return $this; + } + + /** + * @return Target + */ + public function getTarget() + { + return $this->target; + } + + /** + * + * With the folling key/values : + * + * - HTML: The complete HTML version of the email message + * - TEXT: The complete text version of the email message + * - FROM_ADDR: The From address used for the email + * - FROM_NAME: The From name used in the email + * - TO_ADDR: The recipients email address. This is always like following: ~Mail~ + * - TO_NAME: The recipient’s name. This is always like following: ~Name~ + * - REPLY_ADDR: The ‘reply to’ address + * - REPLY_NAME: The ‘reply to’ name + * - SUBJECT: The subject line of the email message + * + * @param Array + * @return self + */ + public function setContent($content) + { + $this->content = $content; + + return $this; + } + + /** + * @return Array + */ + public function getContent() + { + return $this->content; + } +} diff --git a/src/Broadcast/Target.php b/src/Broadcast/Target.php new file mode 100644 index 0000000..4f8e266 --- /dev/null +++ b/src/Broadcast/Target.php @@ -0,0 +1,182 @@ + + * + * For the full license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Mediapart\Selligent\Broadcast; + +/** + * + */ +class Target +{ + const SORTING_ASC = 'ASC'; + const SORTING_DESC = 'DESC'; + + /** + * @var The ID of the selected list as target for the journey map. + */ + private $listId; + + /** + * @var string The field on which the pickup priority for broadcasting is based. + */ + private $priorityField; + + /** + * @var string The sorting applied to the pickup priority field. + */ + private $prioritySorting; + + /** + * @var integer If selected, the ID of the related segment to be used. + */ + private $segmentId; + + /** + * @var string The constraint defined on the targets. + */ + private $constraint; + + /** + * @var Array The profile extensions to include in the target. + */ + private $scopes; + + /** + * + */ + public function __construct() + { + $this->scopes = []; + } + + /** + * @param integer The ID of the selected list as target for the journey map. + * @return self + */ + public function setListId($listId) + { + $this->listId = $listId; + + return $this; + } + + /** + * @return integer The ID of the selected list as target for the journey map. + */ + public function getListId() + { + return $this->listId; + } + + /** + * @param string The field on which the pickup priority for broadcasting is based. + * @return self + */ + public function setPriorityField($priorityField) + { + $this->priorityField = $priorityField; + + return $this; + } + + /** + * @return string The field on which the pickup priority for broadcasting is based. + */ + public function getPriorityField() + { + return $this->priorityField; + } + + /** + * @param string The sorting applied to the pickup priority field. Possible values are ASC and DESC. + * @throws \InvalidArgumentException + * @return self + */ + public function setPrioritySorting($prioritySorting) + { + $possibles = [self::SORTING_ASC, self::SORTING_DESC]; + + if (in_array($prioritySorting, $possibles)) { + $this->prioritySorting = $prioritySorting; + } else { + throw new \InvalidArgumentException(); + } + + return $this; + } + + /** + * @return string The sorting applied to the pickup priority field. + */ + public function getPrioritySorting() + { + return $this->prioritySorting; + } + + /** + * @param integer $segmentId If selected, the ID of the related segment to be used. + * @return self + */ + public function setSegmentId($segmentId) + { + $this->segmentId = $segmentId; + + return $this; + } + + /** + * @return integer If selected, the ID of the related segment to be used. + */ + public function getSegmentId() + { + return $this->segmentId; + } + + /** + * @param string The constraint defined on the targets. + * @return self + */ + public function setConstraint($constraint) + { + $this->constraint = $constraint; + + return $this; + } + + /** + * @return string The constraint defined on the targets. + */ + public function getConstraint() + { + return $this->constraint; + } + + /** + * @param array The profile extensions to include in the target. + * @return Array + */ + public function setScopes($scopes = array()) + { + $this->scopes = $scopes; + + return $this; + } + + /** + * @return string The profile extensions to include in the target. Multiple scopes are separated by a semi colon. + */ + public function getScopes() + { + $scopes = implode(';', $this->scopes); + + return $scopes; + } +} diff --git a/src/Configuration.php b/src/Configuration.php index 17b94d0..9ddd9d8 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -24,13 +24,12 @@ */ class Configuration implements ConfigurationInterface { - /** * Define configTree * @return TreeBuilder */ public function getConfigTreeBuilder() - { + { $treeBuilder = new TreeBuilder(); $rootNode = $treeBuilder->root('selligent'); @@ -67,25 +66,4 @@ public function getConfigTreeBuilder() return $treeBuilder; } - - /** - * load, validate and return configuration - * @param string $configFile - * @return array - */ - public function loadConfig($configFile) - { - if (!empty($configFile)) { - $config = Yaml::parse($configFile); - - $processor = new Processor(); - $processedConfiguration = $processor->processConfiguration( - new Configuration(), - $config - ); - - return $processedConfiguration; - } - } - } diff --git a/src/Connection.php b/src/Connection.php index fe1e081..4713b9a 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -13,6 +13,8 @@ use Psr\Log\LoggerInterface; use Psr\Log\LoggerAwareInterface; +use Symfony\Component\Yaml\Yaml; +use Symfony\Component\Config\Definition\Processor; /** * @@ -29,6 +31,16 @@ class Connection implements LoggerAwareInterface */ const CLASS_SOAPHEADER = 'SoapHeader'; + /** + * @var string + */ + const API_INDIVIDUAL = 'individual.yml'; + + /** + * @var string + */ + const API_BROADCAST = 'broadcast.yml'; + /** * @var ReflectionClass */ @@ -82,29 +94,37 @@ public function setLogger(LoggerInterface $logger) /** - * @param array $config + * @param array $parameters + * @param string $config * * @return \SoapClient */ - public function open(array $config = []) + public function open(array $parameters = [], $config = 'individual.yml') { - $this->options = $config['options']['classmap']; + $processor = new Processor(); + $configuration = $processor->processConfiguration( + new Configuration(), + [ + Yaml::parse(file_get_contents(__DIR__.'/../config/'.$config)), + $parameters + ] + ); if ($this->logger) { - $this->logger->debug(sprintf('connecting to %s', $config['wsdl'])); + $this->logger->debug(sprintf('connecting to %s', $configuration['wsdl'])); } $client = $this ->client - ->newInstance($config['wsdl'], $this->options) + ->newInstance($configuration['wsdl'], $configuration['options']) ; $client->__setSoapHeaders( $this->header->newInstance( - $config['namespace'], + $configuration['namespace'], 'AutomationAuthHeader', [ - 'Login' => $config['login'], - 'Password' => $config['password'], + 'Login' => $configuration['login'], + 'Password' => $configuration['password'], ] ) ); diff --git a/src/Request/CreateCampaign.php b/src/Request/CreateCampaign.php new file mode 100644 index 0000000..99a42d1 --- /dev/null +++ b/src/Request/CreateCampaign.php @@ -0,0 +1,169 @@ + + * + * For the full license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Mediapart\Selligent\Request; + +use Mediapart\Selligent\Broadcast\Campaign; +use Mediapart\Selligent\Broadcast\Target; +use Mediapart\Selligent\Broadcast\Email; + +/** + * + */ +class CreateCampaign +{ + /** + * @var \XMLWriter $writer + */ + private $writer; + + /** + * @param \XMLWriter $writer + */ + public function __construct(\XMLWriter $writer) + { + $writer->openMemory(); + $writer->setIndent(true); + + $this->writer = $writer; + } + + /** + * @param Campaign $campaign + * @return string Xml + */ + public function basedOn(Campaign $campaign) + { + $this->writer->startDocument('1.0'); + $this->writer->startElement('API'); + + $this->campaign($campaign); + $this->emails($campaign->getEmails()); + + $this->writer->endElement(); + $this->writer->endDocument(); + + return $this->writer->outputMemory(TRUE); + } + + /** + * @param string $name + * @param Array $attributes + * @param boolena $end + */ + private function element($name, $attributes = array(), $end = true) + { + $this->writer->startElement($name); + + foreach ($attributes as $key => $value) { + $this->attr($key, $value); + } + + if ($end) { + $this->writer->endElement(); + } + } + + /** + * @param string $name + * @param string $value + */ + private function attr($name, $value) + { + $this->writer->writeAttribute($name, $value); + } + + /** + * @param Campaign $campaign + */ + private function campaign(Campaign $campaign) + { + $this->element( + 'CAMPAIGN', + [ + 'NAME' => $campaign->getName(), + 'STATE' => $campaign->getState(), + 'FOLDERID' => $campaign->getFolderId(), + 'START_DT' => $campaign->getStartDate()->format('Ymdhmi'), + 'DESCRIPTION' => $campaign->getDescription(), + 'MACATEGORY' => $campaign->getMaCategory(), + 'PRODUCTID' => $campaign->getProductId(), + 'CLASHPLANID' => $campaign->getClashPlanId(), + ] + ); + } + + /** + * @param Email[] $emails + */ + private function emails($emails) + { + $this->writer->startElement('EMAILS'); + + foreach ($emails as $email) { + $this->email($email); + } + + $this->writer->endElement(); + } + + /** + * @param Target $target + */ + private function target(Target $target) + { + $this->element( + 'TARGET', + [ + 'LISTID' => $target->getListId(), + 'PRIORITY_FIELD' => $target->getPriorityField(), + 'PRIORITY_SORTING' => $target->getPrioritySorting(), + 'SEGMENTID' => $target->getSegmentId(), + 'CONSTRAINT' => $target->getConstraint(), + 'SCOPES' => $target->getScopes(), + ] + ); + } + + /** + * @param Email $email + */ + private function email(Email $email) + { + $this->element( + 'EMAIL', + [ + 'NAME' => $email->getName(), + 'FOLDERID' => $email->getFolderId(), + 'MAILDOMAINID' => $email->getMailDomainId(), + 'LIST_UNSUBSCRIBE' => $email->canUnsubscribe() ? 'TRUE' : 'FALSE', + 'QUEUEID' => $email->getQueueId(), + 'TAG' => $email->getTag(), + 'MACATEGORY' => $email->getMaCategory(), + ], + false + ); + + $this->target($email->getTarget()); + + $this->writer->startElement('CONTENT'); + foreach ($email->getContent() as $key => $value) { + $this->writer->startElement($key); + $this->writer->startCData(); + $this->writer->text($value); + $this->writer->endCData(); + $this->writer->endElement(); + } + $this->writer->endElement(); + + $this->writer->endElement(); + } +} diff --git a/src/Response/CreateCampaignResponse.php b/src/Response/CreateCampaignResponse.php new file mode 100644 index 0000000..db643a9 --- /dev/null +++ b/src/Response/CreateCampaignResponse.php @@ -0,0 +1,66 @@ + + * + * For the full license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Mediapart\Selligent\Response; + +use Mediapart\Selligent\Response; + +/** + * + */ +class CreateCampaignResponse extends Response +{ + /** + * + */ + const WARNING = 20001; + + /** + * @var integer + */ + protected $CreateCampaignResult; + + /** + * @var string + */ + protected $Xml; + + /** + * + */ + public function __construct() + { + $this->CreateCampaignResult = Response::ERROR_NORESULT; + $this->Xml = ''; + } + + /** + * {@inheritDoc} + */ + public function getCode() + { + if (self::SUCCESSFUL == $this->CreateCampaignResult && !empty($this->ErrorStr)) { + $code = self::WARNING; + } else { + $code = $this->CreateCampaignResult; + } + + return $code; + } + + /** + * @return string Xml + */ + public function getXml() + { + return $this->Xml; + } +} diff --git a/src/Response/GetSegmentRecordCountResponse.php b/src/Response/GetSegmentRecordCountResponse.php index 5680813..442a144 100644 --- a/src/Response/GetSegmentRecordCountResponse.php +++ b/src/Response/GetSegmentRecordCountResponse.php @@ -28,6 +28,12 @@ class GetSegmentRecordCountResponse extends Response */ protected $segmentCount; + public function __construct() + { + $this->GetSegmentRecordCountResult = Response::ERROR_NORESULT; + $this->segmentCount = 0; + } + /** * {@inheritDoc} */ diff --git a/src/Response/GetSegmentsResponse.php b/src/Response/GetSegmentsResponse.php index d6bdc1d..5084e08 100644 --- a/src/Response/GetSegmentsResponse.php +++ b/src/Response/GetSegmentsResponse.php @@ -29,6 +29,12 @@ class GetSegmentsResponse extends Response */ protected $segments; + public function __construct() + { + $this->GetSegmentsResult = Response::ERROR_NORESULT; + $this->segments = []; + } + /** * {@inheritDoc} */ diff --git a/tests/Broadcast/CampaignTest.php b/tests/Broadcast/CampaignTest.php new file mode 100644 index 0000000..70e792a --- /dev/null +++ b/tests/Broadcast/CampaignTest.php @@ -0,0 +1,142 @@ + + * + * For the full license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Mediapart\Selligent\Broadcast; + +use Mediapart\Selligent\Request\CreateCampaign; +use \XMLWriter; + +/** + * + */ +class CampaignTest extends \PHPUnit_Framework_TestCase +{ + /** + * + */ + public function testWrongCampaignState() + { + $campaign = new Campaign(); + + $this->setExpectedException(\InvalidArgumentException::class); + + $campaign->setState('Lorem ipsum dolor'); + } + + /** + * + */ + public function testXml() + { + $campaign = $this->getCampaign(); + $writer = new XMLWriter(); + $request = new CreateCampaign($writer); + + $xml = $request->basedOn($campaign); + + $document = simplexml_load_string($xml); + $this->assertEquals($campaign->getName(), (string) $document->CAMPAIGN['NAME']); + $this->assertEquals($campaign->getFolderId(), (int) $document->CAMPAIGN['FOLDERID']); + $this->assertEquals($campaign->getState(), (string) $document->CAMPAIGN['STATE']); + $this->assertEquals($campaign->getStartDate()->format('Ymdhmi'), (string) $document->CAMPAIGN['START_DT']); + $this->assertEquals($campaign->getDescription(), (string) $document->CAMPAIGN['DESCRIPTION']); + $this->assertEquals($campaign->getMaCategory(), (string) $document->CAMPAIGN['MACATEGORY']); + $this->assertEquals($campaign->getProductId(), (int) $document->CAMPAIGN['PRODUCTID']); + $this->assertEquals($campaign->getClashPlanId(), (int) $document->CAMPAIGN['CLASHPLANID']); + + $emails = $campaign->getEmails(); + $this->assertEquals(count($emails), (int) $document->EMAILS->count()); + for ($i=0; $i<$document->EMAILS->count(); $i++) { + $email = $emails[$i]; + + $node = $document->EMAILS->EMAIL[$i]; + $this->assertEquals($email->getName(), (string) $node['NAME']); + $this->assertEquals($email->getFolderId(), (int) $node['FOLDERID']); + $this->assertEquals($email->getMailDomainId(), (int) $node['MAILDOMAINID']); + $this->assertEquals($email->canUnsubscribe() ? 'TRUE' : 'FALSE', (string) $node['LIST_UNSUBSCRIBE']); + $this->assertEquals($email->getQueueId(), (int) $node['QUEUEID']); + $this->assertEquals($email->getTag(), (string) $node['TAG']); + $this->assertEquals($email->getMaCategory(), (string) $node['MACATEGORY']); + + $target = $email->getTarget(); + $this->assertEquals($target->getListId(), (int) $node->TARGET['LISTID']); + $this->assertEquals($target->getPriorityField(), (string) $node->TARGET['PRIORITY_FIELD']); + $this->assertEquals($target->getPrioritySorting(), (string) $node->TARGET['PRIORITY_SORTING']); + $this->assertEquals($target->getSegmentId(), (int) $node->TARGET['SEGMENTID']); + $this->assertEquals($target->getConstraint(), (string) $node->TARGET['CONSTRAstring']); + $this->assertEquals($target->getScopes(), (string) $node->TARGET['SCOPES']); + + $this->assertEquals($email->getContent()['HTML'], (string) $node->CONTENT->HTML); + $this->assertEquals($email->getContent()['TEXT'], (string) $node->CONTENT->TEXT); + $this->assertEquals($email->getContent()['FROM_ADDR'], (string) $node->CONTENT->FROM_ADDR); + $this->assertEquals($email->getContent()['FROM_NAME'], (string) $node->CONTENT->FROM_NAME); + $this->assertEquals($email->getContent()['TO_NAME'], (string) $node->CONTENT->TO_NAME); + $this->assertEquals($email->getContent()['TO_ADDR'], (string) $node->CONTENT->TO_ADDR); + $this->assertEquals($email->getContent()['REPLY_NAME'], (string) $node->CONTENT->REPLY_NAME); + $this->assertEquals($email->getContent()['REPLY_ADDR'], (string) $node->CONTENT->REPLY_ADDR); + $this->assertEquals($email->getContent()['SUBJECT'], (string) $node->CONTENT->SUBJECT); + } + } + + /** + * @return Campaign + */ + private function getCampaign() + { + $campaign = new Campaign(); + $campaign + ->setName('DailY IT News 20090801') + ->setFolderId(5) + ->setState(Campaign::DESIGN) + ->setStartDate(new \DateTime('tomorrow')) + ->setDescription('My-Description') + ->setMaCategory('Science') + ->setProductId(1) + ->setClashPlanId(0) + ; + + $target = new Target(); + $target + ->setListId(13) + ->setPriorityField('CREATED_DT') + ->setPrioritySorting('DESC') + ->setSegmentid(2) + ->setConstraint('') + ->setScopes(['foo', 'bar']) + ; + + $email = new Email(); + $email + ->setName('DailY IT News 20090801') + ->setFolderId(5) + ->setMailDomainId(1) + ->listUnsubscribe(true) + ->setQueueId(1) + ->setTag('') + ->setMaCategory('Science') + ->setTarget($target) + ->setContent([ + 'HTML' => 'du html ici', + 'TEXT' => 'du texte là', + 'FROM_ADDR' => 'demo@emsecure.net', + 'FROM_NAME' => 'SIM Training', + 'TO_ADDR' => '~MAIL~', + 'TO_NAME' => '~NAME~', + 'REPLY_ADDR' => 'noreply@emsecure.net', + 'REPLY_NAME' => 'SIM Training', + 'SUBJECT' => 'Daily IT News - Optus survey finds iPhone 3G getting strong traction in the enterprise, Asus Eee PC T91 Tablet PC, ...', + ]) + ; + $campaign->addEmail($email); + + return $campaign; + } +} diff --git a/tests/Broadcast/TargetTest.php b/tests/Broadcast/TargetTest.php new file mode 100644 index 0000000..27f216d --- /dev/null +++ b/tests/Broadcast/TargetTest.php @@ -0,0 +1,27 @@ + + * + * For the full license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Mediapart\Selligent\Broadcast; + +/** + * + */ +class TargetTest extends \PHPUnit_Framework_TestCase +{ + public function testSetPrioritySortingWithException() + { + $target = new Target(); + + $this->setExpectedException(\InvalidArgumentException::class); + + $target->setPrioritySorting('lorem'); + } +} diff --git a/tests/BroadcastTest.php b/tests/BroadcastTest.php new file mode 100644 index 0000000..7397e94 --- /dev/null +++ b/tests/BroadcastTest.php @@ -0,0 +1,104 @@ + + * + * For the full license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Mediapart\Selligent; + +use \XMLWriter; +use Mediapart\Selligent\Response; +use Mediapart\Selligent\Broadcast\Campaign; +use Mediapart\Selligent\Broadcast\Target; +use Mediapart\Selligent\Broadcast\Email; +use Mediapart\Selligent\Request\CreateCampaign; + +/** + * + */ +class BroadcastTest extends \PHPUnit_Framework_TestCase +{ + /** + * + */ + public function __construct() + { + $con = new Connection(); + $this->client = $con->open( + [ + 'login' => getenv('soap_login'), + 'password' => getenv('soap_password'), + 'wsdl' => getenv('soap_wsdl_broadcast'), + 'list' => getenv('selligent_list'), + ], + Connection::API_BROADCAST + ); + } + + /** + * + */ + public function testCompleteHTML() + { + $tomorrow = new \DateTime('tomorrow'); + + $campaign = new Campaign(); + $campaign + ->setName('Broadcast Test ('.$tomorrow->format('l, jS F').')') + ->setFolderId(getenv('selligent_folderid')) + ->setState(Campaign::ACTIVE) + ->setStartDate($tomorrow) + ->setDescription(sprintf( + 'Some broadcast test scheduled for the %s at %s.', + $tomorrow->format('L, jS F'), + $tomorrow->format('g:ia') + )) + ; + $target = new Target(); + $target + ->setListId(getenv('selligent_listid')) + ->setPriorityField('CREATED_DT') + ->setPrioritySorting('DESC') + ->setSegmentid(getenv('selligent_segmentid')) + ; + $email = new Email(); + $email + ->setName('Broadcast Email Test ('.$tomorrow->format('l, jS F').')') + ->setFolderId(getenv('selligent_folderid')) + ->setMailDomainId(getenv('selligent_maildomainid')) + ->listUnsubscribe(false) + ->setQueueId(getenv('selligent_queueid')) + ->setMaCategory(getenv('selligent_macategory')) + ->setTarget($target) + ->setContent([ + 'HTML' => 'html over here.', + 'TEXT' => 'text over there.', + 'FROM_ADDR' => 'from@domain.tld', + 'FROM_NAME' => 'From Name', + 'TO_ADDR' => '~MAIL~', + 'TO_NAME' => '~NAME~', + 'REPLY_ADDR' => 'reply-to@domain.tld', + 'REPLY_NAME' => 'Reply To', + 'SUBJECT' => sprintf( + '%s at %s.', + $tomorrow->format('l, jS F'), + $tomorrow->format('g:ia') + ), + ]) + ; + $campaign->addEmail($email); + + $writer = new XMLWriter(); + $request = new CreateCampaign($writer); + $xml = $request->basedOn($campaign); + $response = $this->client->CreateCampaign(['Xml' => $xml]); + + $this->assertEquals('', $response->getError()); + $this->assertEquals(Response::SUCCESSFUL, $response->getCode()); + } +} diff --git a/tests/ConfigurationTest.php b/tests/ConfigurationTest.php index 24e9e1e..2dede63 100644 --- a/tests/ConfigurationTest.php +++ b/tests/ConfigurationTest.php @@ -11,31 +11,32 @@ namespace Mediapart\Selligent; +use Symfony\Component\Yaml\Yaml; +use Symfony\Component\Config\Definition\Processor; + /** * */ class ConfigurationTest extends \PHPUnit_Framework_TestCase { - - public function testConfigurationKO() + public function testConfiguration() { - $this->setExpectedException('\Symfony\Component\Config\Definition\Exception\InvalidConfigurationException'); - - $configFile = file_get_contents(__DIR__.'/test_config_ko.yaml'); - $cfg = new Configuration(); - - $cfg->loadConfig($configFile); - } - - public function testCheckReturnedConfig() - { - $configFile = file_get_contents(__DIR__.'/test_config_ok.yaml'); - $fixture = ['login' => 'MY_LOGIN', 'namespace' => "http://tempuri.org/"]; - $cfg = new Configuration(); - - $config = $cfg->loadConfig($configFile); - - $this->assertEquals($fixture['login'], $config['login']); - $this->assertEquals($fixture['namespace'], $config['namespace']); + $config = [ + 'login' => 'login', + 'password' => 'password', + 'wsdl' => 'http//wsdl?individual', + 'list' => 'LISTNAME', + ]; + $processor = new Processor(); + $configuration = new Configuration(); + + $processedConfiguration = $processor->processConfiguration( + $configuration, + [$config] + ); + + $this->assertEquals('login', $processedConfiguration['login']); + $this->assertEquals('password', $processedConfiguration['password']); + $this->assertEquals('http://tempuri.org/', $processedConfiguration['namespace']); } } \ No newline at end of file diff --git a/tests/ConnectionTest.php b/tests/ConnectionTest.php index d91977f..91823c8 100644 --- a/tests/ConnectionTest.php +++ b/tests/ConnectionTest.php @@ -21,22 +21,12 @@ class ConnectionTest extends \PHPUnit_Framework_TestCase */ public function testConnection() { - $config = [ - 'selligent' => [ + $connection = new Connection(); + $client = $connection->open([ 'login' => 'login', 'password' => 'password', 'wsdl' => 'tests/individual.xml', - 'namespace' => 'http://tempuri.org/', - 'options' => [ - 'classmap' => [ - 'CountUsersByConstraint' => '' - ] - ] - ] - ]; - - $connection = new Connection(); - $client = $connection->open($config['selligent']); + ]); $this->assertInstanceOf(Connection::CLASS_SOAPCLIENT, $client); } @@ -75,22 +65,12 @@ public function testConnectionWithLogger() ->method('debug') ; - $config = [ - 'selligent' => [ - 'login' => '', - 'password' => '', - 'wsdl' => 'tests/individual.xml', - 'namespace' => 'http://tempuri.org/', - 'options' => [ - 'classmap' => [ - 'CountUsersByConstraint' => '' - ] - ] - ] - ]; - $connection = new Connection(); $connection->setLogger($logger); - $connection->open($config['selligent']); + $connection->open([ + 'login' => 'somelogin', + 'password' => 'somepassword', + 'wsdl' => 'tests/individual.xml', + ]); } } diff --git a/tests/RealTest.php b/tests/IndividualTest.php similarity index 87% rename from tests/RealTest.php rename to tests/IndividualTest.php index 0c574b8..9dc528f 100644 --- a/tests/RealTest.php +++ b/tests/IndividualTest.php @@ -11,10 +11,14 @@ namespace Mediapart\Selligent; +use Symfony\Component\Yaml\Yaml; +use Symfony\Component\Config\Definition\Processor; +use Mediapart\Selligent\Configuration; + /** * */ -class RealTest extends \PHPUnit_Framework_TestCase +class IndividualTest extends \PHPUnit_Framework_TestCase { const API_VERSION = 'v6.3'; @@ -38,28 +42,21 @@ class RealTest extends \PHPUnit_Framework_TestCase */ public function __construct() { - $config = [ - 'selligent' => [ - 'login' => getenv('soap_login'), - 'password' => getenv('soap_password'), - 'wsdl' => getenv('soap_wsdl'), - 'namespace' => 'http://tempuri.org/', - 'list' => getenv('selligent_list'), - 'options' => [ - 'classmap' => [ - 'CountUsersByConstraint' => '' - ] - ] - ] - ]; - $con = new Connection(); - $this->client = $con->open($config['selligent']); + $this->client = $con->open( + [ + 'login' => getenv('soap_login'), + 'password' => getenv('soap_password'), + 'wsdl' => getenv('soap_wsdl_individual'), + 'list' => getenv('selligent_list'), + ], + Connection::API_INDIVIDUAL + ); $response = $this ->client ->getListID([ - 'name' => $config['selligent']['list'], + 'name' => getenv('selligent_list'), ]) ; diff --git a/tests/Response/CreateCampaignResponseTest.php b/tests/Response/CreateCampaignResponseTest.php new file mode 100644 index 0000000..c15a034 --- /dev/null +++ b/tests/Response/CreateCampaignResponseTest.php @@ -0,0 +1,49 @@ + + * + * For the full license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Mediapart\Selligent\Response; + +use Mediapart\Selligent\Response; + +/** + * + */ +class CreateCampaignResponseTest extends \PHPUnit_Framework_TestCase +{ + /** + * + */ + public function testResponse() + { + $response = new CreateCampaignResponse(); + + $this->assertEquals('', $response->getXml()); + $this->assertEquals(Response::ERROR_NORESULT, $response->getCode()); + } + + /** + * + */ + public function testResponseWithWarning() + { + $class = 'Mediapart\Selligent\Response\CreateCampaignResponse'; + $response = new CreateCampaignResponse(); + + $property = new \ReflectionProperty($class, 'ErrorStr'); + $property->setAccessible(true); + $property->setValue($response, 'Lorem'); + $property = new \ReflectionProperty($class, 'CreateCampaignResult'); + $property->setAccessible(true); + $property->setValue($response, Response::SUCCESSFUL); + + $this->assertEquals(CreateCampaignResponse::WARNING, $response->getCode()); + } +} diff --git a/tests/Response/GetSegmentRecordCountResponseTest.php b/tests/Response/GetSegmentRecordCountResponseTest.php new file mode 100644 index 0000000..63deb57 --- /dev/null +++ b/tests/Response/GetSegmentRecordCountResponseTest.php @@ -0,0 +1,31 @@ + + * + * For the full license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Mediapart\Selligent\Response; + +use Mediapart\Selligent\Response; + +/** + * + */ +class GetSegmentRecordCountResponseTest extends \PHPUnit_Framework_TestCase +{ + /** + * + */ + public function testResponse() + { + $response = new GetSegmentRecordCountResponse(); + + $this->assertEquals(Response::ERROR_NORESULT, $response->getCode()); + $this->assertEquals(0, $response->getResult()); + } +} diff --git a/tests/Response/GetSegmentsResponseTest.php b/tests/Response/GetSegmentsResponseTest.php new file mode 100644 index 0000000..9b0d223 --- /dev/null +++ b/tests/Response/GetSegmentsResponseTest.php @@ -0,0 +1,31 @@ + + * + * For the full license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Mediapart\Selligent\Response; + +use Mediapart\Selligent\Response; + +/** + * + */ +class GetSegmentsResponseTest extends \PHPUnit_Framework_TestCase +{ + /** + * + */ + public function testResponse() + { + $response = new GetSegmentsResponse(); + + $this->assertEquals(Response::ERROR_NORESULT, $response->getCode()); + $this->assertEquals([], $response->getSegments()); + } +} diff --git a/tests/test_config_ko.yaml b/tests/test_config_ko.yaml deleted file mode 100644 index bcbce1c..0000000 --- a/tests/test_config_ko.yaml +++ /dev/null @@ -1,9 +0,0 @@ -selligent: - login: "" - password: "MY_PWD" - namespace: "http://tempuri.org/" - wsdl: "https://emsecure.net/automation/broadcast.asmx?WSDL" - list: "MY_LIST" - options: - classmap: - CreateCampaign: "MY_PATH" diff --git a/tests/test_config_ok.yaml b/tests/test_config_ok.yaml deleted file mode 100644 index 0d9acf8..0000000 --- a/tests/test_config_ok.yaml +++ /dev/null @@ -1,9 +0,0 @@ -selligent: - login: "MY_LOGIN" - password: "MY_PWD" - namespace: "http://tempuri.org/" - wsdl: "https://emsecure.net/automation/broadcast.asmx?WSDL" - list: "MY_LIST" - options: - classmap: - CreateCampaign: "MY_PATH"