├── .github
└── workflows
│ └── test.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── composer.json
├── src
├── Ad
│ ├── AbstractAdNode.php
│ ├── InLine.php
│ └── Wrapper.php
├── Creative
│ ├── AbstractCreative.php
│ ├── AbstractLinearCreative.php
│ ├── InLine
│ │ ├── Linear.php
│ │ └── Linear
│ │ │ ├── ClosedCaptionFile.php
│ │ │ ├── InteractiveCreativeFile.php
│ │ │ └── MediaFile.php
│ └── Wrapper
│ │ └── Linear.php
├── Document.php
├── Document
│ └── AbstractNode.php
├── ElementBuilder.php
└── Factory.php
└── tests
├── .phpunit.cache
└── test-results
├── AbstractTestCase.php
├── DocumentTest.php
├── ElementBuilderTest.php
├── FactoryTest.php
├── Stub
└── CustomElementBuilder
│ ├── CustomElementBuilder.php
│ └── Element
│ ├── CustomDocument.php
│ ├── CustomInLine.php
│ ├── CustomInLineAdLinearCreative.php
│ ├── CustomMediaFile.php
│ ├── CustomWrapper.php
│ └── CustomWrapperAdLinearCreative.php
├── data
├── adWithDelivery.xml
├── error.xml
├── errorInInline.xml
├── errorInWrapper.xml
├── impressionInWrapper.xml
├── inlineAd.xml
├── inlineAdCustomElements.xml
├── inlineAdWithExtension.xml
├── linearCreativeWithClosedCaption.xml
├── linearCreativeWithClosedCaptionAndMediaFile.xml
├── linearCreativeWithInteractiveCreativeAndMediaFile.xml
├── linearCreativeWithSkipAfter.xml
├── linearCreativeWithStreamingDelivery.xml
├── replacedClickThrough.xml
├── vast.xml
├── vpaid.xml
├── wrapper.xml
└── wrapperAdWithExtension.xml
└── phpunit.xml
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Test
2 |
3 | on:
4 | push:
5 | branches: [ "2.0" ]
6 | pull_request:
7 | branches: [ "2.0" ]
8 |
9 | jobs:
10 | test:
11 | runs-on: ubuntu-latest
12 |
13 | strategy:
14 | matrix:
15 | php-version:
16 | - "7.3"
17 | - "7.4"
18 | - "8.0"
19 | - "8.1"
20 | - "8.2"
21 |
22 | steps:
23 | - uses: actions/checkout@v2
24 |
25 | - name: Setup PHP
26 | uses: shivammathur/setup-php@v2
27 | with:
28 | php-version: ${{ matrix.php-version }}
29 | ini-values: post_max_size=256M, max_execution_time=180
30 |
31 | - name: Validate composer.json and composer.lock
32 | run: composer validate
33 |
34 | - name: Cache Composer packages
35 | id: composer-cache
36 | uses: actions/cache@v2
37 | with:
38 | path: vendor
39 | key: ${{ runner.os }}-composer-${{ matrix.php-version }}-${{ hashFiles('**/composer.lock') }}
40 | restore-keys: |
41 | ${{ runner.os }}-composer-
42 |
43 | - name: Install dependencies
44 | if: steps.composer-cache.outputs.cache-hit != 'true'
45 | run: composer install --dev --prefer-dist --no-progress --no-suggest
46 |
47 | - name: Prepare dir
48 | run: mkdir -p build/logs
49 |
50 | - name: Run test suite
51 | run: composer cover
52 |
53 | - name: Upload coverage results to Coveralls
54 | env:
55 | COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
56 | run: composer coveralls
57 |
58 | quality:
59 | runs-on: ubuntu-latest
60 |
61 | steps:
62 | - uses: actions/checkout@v2
63 |
64 | - name: Setup PHP
65 | uses: shivammathur/setup-php@v2
66 | with:
67 | php-version: "7.4"
68 | ini-values: post_max_size=256M, max_execution_time=180
69 |
70 | - name: Install dependencies
71 | if: steps.composer-cache.outputs.cache-hit != 'true'
72 | run: composer install --prefer-dist --no-progress --no-suggest
73 |
74 | - name: Run style checks
75 | run: composer check-style
76 |
77 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor
2 | composer.lock
3 | tests/.phpunit.result.cache
4 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 2.2.1 (2023-01-29)
2 | * Allows setting the `Description` and `AdServingId` of an `Inline` ad.
3 |
4 | ## 2.2.0 (2023-01-29)
5 | * Add support for InteractiveCreativeFile as per 4.1 VAST specification
6 |
7 | ## 2.1.0 (2021-01-23)
8 | * PHP 8 Support
9 |
10 | ## 2.0 (2019-09-26)
11 | * Support PHP 7.1.3 and above
12 | * Removed deprecated Document::toString(), use casting object to string
13 | * Removed deprecated document builders Document::create(), Document::fromFile(), Document::fromString(), use Factory instead
14 |
15 | ## 1.0 (2019-09-26)
16 | * Support Closed Caption Files
17 | * Version 1.0 supports PHP 5.3 - 7.3
18 |
19 | ## 0.6 (2019-09-06)
20 | * Added support of `id` and `adId` attributes of `creative` element.
21 | * Added ability to create own elements and attributes through custom `ElementBuilder`, see [Custom Specification Support](https://github.com/sokil/php-vast#custom-specification-support) section of manual.
22 |
23 | ## 0.5.3 (2019-05-06)
24 | * UniversalAdId added due to VAST 4.0 specification. UniversalAdId required in response beginning with VAST 4.0 (paragraph 3.7.1)
25 |
26 | ## 0.5.2 (2019-03-23)
27 | * Add offset to progress event tracking. See specification 2.3.2.3 "Progress Event".
28 |
29 | ## 0.5.1 (2018-10-31)
30 | * Allow specify `adParameter` and `apiFramework`.
31 |
32 | ## 0.4.8 (2018-06-29)
33 | * Fixed 'Document::getAdSections()'. Previously root DOM element was set to first child which may be text node. Now it points to `InLine` or `Wrapper` element.
34 | * Now may be specified id of `Impression` in `AbstractAdNode::addImpression`
35 |
36 | ## 0.4.7 (2018-06-29)
37 | * Fixed `AbstractNode::getValuesOfArrayNode`. Affected `AbstractAdNode::getErrors()` and `AbstractAdNode::getImpressions()` if multiple nodes in array found. Array always contain first node instead of values of all nodes.
38 |
39 | ## 0.4.6 (2018-04-05)
40 | * Fix adding Extension to Ad\InLine section
41 | * Now Extensions can be created for Ad\Wrapper also
42 |
43 | ## 0.4.5 (2018-02-22)
44 | * Method `AbstractAdNode::getSequence` now return int instead of numeric string
45 |
46 | ## 0.4.4 (2018-01-25)
47 | * Allow Ad sequence
48 |
49 | ## 0.4.2 (2017-11-02)
50 | * Returned method `AbstractAdNode::setImpression` and marked deprecated
51 |
52 | ## 0.4 (2017-07-26)
53 | * Move to PSR-4
54 | * Added `Factory` to create document. Factory methods in `Document` are deprecated
55 | * Added `Error` tag to `VAST`, `InLine` and `Wrapper`
56 | * Allowed to add multiple `Impression` to `InLine` and `Wrapper`
57 | * Removed method `AbstractAdNode::setImpression`
58 | * Classes moved. Check your extends
59 |
60 | ## 0.3 (2016-03-24)
61 | * Add support of Wrapper's VASTAdTagURI element
62 | * Private methods and properties now without underscores
63 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013-2019 Dmytro Sokil
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is furnished
8 | to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Stand With Ukraine
2 |
3 | [](https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md)
4 |
5 | ----
6 |
7 | PHP-VAST
8 | ========
9 |
10 | [](https://github.com/sokil/php-vast/actions?query=workflow%3ATest)
11 | [](https://packagist.org/packages/sokil/php-vast)
12 | [](https://coveralls.io/github/sokil/php-vast?branch=master)
13 |
14 | :star: VAST Ad generator and parser library on PHP.
15 |
16 | ## Specs
17 | * VAST 2.0 Spec: http://www.iab.net/media/file/VAST-2_0-FINAL.pdf
18 | * VAST 3.0 Spec: http://www.iab.com/wp-content/uploads/2015/06/VASTv3_0.pdf
19 | * VAST 4.0 Spec:
20 | * http://www.iab.com/wp-content/uploads/2016/01/VAST_4-0_2016-01-21.pdf
21 | * https://www.iab.com/wp-content/uploads/2016/04/VAST4.0_Updated_April_2016.pdf
22 | * VAST 4.1 Spec:
23 | * https://iabtechlab.com/wp-content/uploads/2018/11/VAST4.1-final-Nov-8-2018.pdf
24 | * [VAST Samples](https://github.com/InteractiveAdvertisingBureau/VAST_Samples)
25 |
26 | ## Install
27 |
28 | Install library through composer:
29 |
30 | ```
31 | composer require sokil/php-vast
32 | ```
33 |
34 | ## Quick start
35 |
36 | ```php
37 | // create document
38 | $factory = new \Sokil\Vast\Factory();
39 | $document = $factory->create('4.1');
40 |
41 | // insert Ad section
42 | $ad1 = $document
43 | ->createInLineAdSection()
44 | ->setId('ad1')
45 | ->setAdSystem('Ad Server Name')
46 | ->setAdTitle('Ad Title')
47 | ->addImpression('http://ad.server.com/impression', 'imp1');
48 |
49 | // create creative for ad section
50 | $linearCreative = $ad1
51 | ->createLinearCreative()
52 | ->setDuration(128)
53 | ->setId('013d876d-14fc-49a2-aefd-744fce68365b')
54 | ->setAdId('pre')
55 | ->setVideoClicksClickThrough('http://entertainmentserver.com/landing')
56 | ->addVideoClicksClickTracking('http://ad.server.com/videoclicks/clicktracking')
57 | ->addVideoClicksCustomClick('http://ad.server.com/videoclicks/customclick')
58 | ->addTrackingEvent('start', 'http://ad.server.com/trackingevent/start')
59 | ->addTrackingEvent('pause', 'http://ad.server.com/trackingevent/stop');
60 |
61 | // add closed caption file (Closed Caption support starts on VAST 4.1)
62 | $linearCreative
63 | ->createClosedCaptionFile()
64 | ->setLanguage('en-US')
65 | ->setType('text/srt')
66 | ->setUrl('http://server.com/cc.srt');
67 |
68 | // add 100x100 media file
69 | $linearCreative
70 | ->createMediaFile()
71 | ->setProgressiveDelivery()
72 | ->setType('video/mp4')
73 | ->setHeight(100)
74 | ->setWidth(100)
75 | ->setBitrate(2500)
76 | ->setUrl('http://server.com/media1.mp4');
77 |
78 | // add 200x200 media file
79 | $linearCreative
80 | ->createMediaFile()
81 | ->setProgressiveDelivery()
82 | ->setType('video/mp4')
83 | ->setHeight(200)
84 | ->setWidth(200)
85 | ->setBitrate(2500)
86 | ->setUrl('http://server.com/media2.mp4');
87 |
88 | // get dom document
89 | $domDocument = $document->toDomDocument();
90 |
91 | // get XML string
92 | echo $document;
93 | ```
94 |
95 | This will generate:
96 |
97 | ```xml
98 |
99 |
100 |
101 |
102 | Ad Server Name
103 |
104 |
105 |
106 |
107 |
108 | 00:02:08
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 | ```
138 |
139 | ## Custom Specification Support
140 |
141 | VAST document elements are completely described in it's specification, but some Ad servers may add support for custom elements and attributes. This library strictly follows specification, generally because two dialects of VAST may conflict with each other. You may write our own dialect by overriding element builder and create any elements and attributes you want.
142 |
143 | The VAST dialect is described in `\Sokil\Vast\ElementBuilder` class. By overriding it you may create instances of your own classes and add there any setters.
144 |
145 | First let's create a class for `MediaFile` and add some custom attributes:
146 |
147 | ```php
148 | domElement->setAttribute('minDuration', $seconds);
164 |
165 | return $this;
166 | }
167 | }
168 | ```
169 |
170 | Now we need to override the default element builder and create our own `MediaFile` factory method:
171 |
172 | ```php
173 |
184 | *
185 | * @param \DOMElement $mediaFileDomElement
186 | *
187 | * @return AcmeMediaFile
188 | */
189 | public function createInLineAdLinearCreativeMediaFile(\DOMElement $mediaFileDomElement)
190 | {
191 | return new AcmeMediaFile($mediaFileDomElement);
192 | }
193 | }
194 | ```
195 |
196 | Now we need to confugure VAST factory to use overridden element builder:
197 |
198 | ```php
199 | create('4.1');
208 |
209 | $ad = $document->createInLineAdSection();
210 | $creative = $ad->createLinearCreative();
211 | $mediaFile = $creative->createMediaFile();
212 |
213 | $mediaFile->setMinDiration(10);
214 | ```
215 |
216 | If you have an AD server and want to add support for your custom tag, create your own library with custom elements and element builder, or add a pull request to this library.
217 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sokil/php-vast",
3 | "description": "Generator and parser for VAST documents",
4 | "authors": [
5 | {
6 | "name": "Dmytro Sokil",
7 | "email": "dmytro.sokil@gmail.com"
8 | }
9 | ],
10 | "license": "MIT",
11 | "require": {
12 | "php": ">=7.1.3",
13 | "ext-dom": "*",
14 | "ext-json": "*"
15 | },
16 | "require-dev": {
17 | "phpunit/phpunit": ">=7.5.20",
18 | "php-coveralls/php-coveralls": "^2.1",
19 | "squizlabs/php_codesniffer": "^3.4.2"
20 | },
21 | "autoload": {
22 | "psr-4": {
23 | "Sokil\\Vast\\": ["src/"]
24 | }
25 | },
26 | "autoload-dev": {
27 | "psr-4": {
28 | "Sokil\\Vast\\": ["tests/"]
29 | }
30 | },
31 | "scripts": {
32 | "test": "./vendor/bin/phpunit -c ./tests/phpunit.xml",
33 | "cover": "./vendor/bin/phpunit -c ./tests/phpunit.xml --coverage-clover build/logs/clover.xml",
34 | "coveralls": "./vendor/bin/php-coveralls -v",
35 | "check-style": "./vendor/bin/phpcs -p --standard=PSR2 --runtime-set ignore_errors_on_exit 1 --runtime-set ignore_warnings_on_exit 1 src",
36 | "fix-style": "./vendor/bin/phpcbf -p --standard=PSR2 --runtime-set ignore_errors_on_exit 1 --runtime-set ignore_warnings_on_exit 1 src"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Ad/AbstractAdNode.php:
--------------------------------------------------------------------------------
1 |
8 | *
9 | * For the full copyright and license information, please view the LICENSE
10 | * file that was distributed with this source code.
11 | */
12 |
13 | namespace Sokil\Vast\Ad;
14 |
15 | use Sokil\Vast\Creative\AbstractCreative;
16 | use Sokil\Vast\Document\AbstractNode;
17 | use Sokil\Vast\ElementBuilder;
18 |
19 | abstract class AbstractAdNode extends AbstractNode
20 | {
21 | /**
22 | * @var \DOMElement
23 | */
24 | private $domElement;
25 |
26 | /**
27 | * @var ElementBuilder
28 | */
29 | protected $vastElementBuilder;
30 |
31 | /**
32 | * @var \DOMElement
33 | */
34 | private $adDomElement;
35 |
36 | /**
37 | * Creatives
38 | *
39 | * @var array
40 | */
41 | private $creatives = [];
42 |
43 | /**
44 | * @var \DomElement
45 | */
46 | private $creativesDomElement;
47 |
48 | /**
49 | * @var \DomElement
50 | */
51 | private $extensionsDomElement;
52 |
53 | /**
54 | * @param \DOMElement $adDomElement instance of \Vast\Ad element
55 | * @param ElementBuilder $vastElementBuilder
56 | */
57 | public function __construct(\DOMElement $adDomElement, ElementBuilder $vastElementBuilder)
58 | {
59 | $this->adDomElement = $adDomElement;
60 | $this->domElement = $this->adDomElement->getElementsByTagName($this->getAdSubElementTagName())->item(0);
61 | $this->vastElementBuilder = $vastElementBuilder;
62 | }
63 |
64 | /**
65 | * Return type of ad (InLine or Wrapper)
66 | *
67 | * @return string
68 | */
69 | abstract public function getAdSubElementTagName(): string;
70 |
71 | /**
72 | * Instance of "\Vast\Ad\(InLine|Wrapper)" element
73 | *
74 | * @return \DOMElement
75 | */
76 | protected function getDomElement(): \DOMElement
77 | {
78 | return $this->domElement;
79 | }
80 |
81 | /**
82 | * Get id for Ad element
83 | *
84 | * @return string
85 | */
86 | public function getId(): string
87 | {
88 | return $this->adDomElement->getAttribute('id');
89 | }
90 |
91 | /**
92 | * Set 'id' attribute of 'ad' element
93 | *
94 | * @param string $id
95 | *
96 | * @return InLine|Wrapper|AbstractAdNode
97 | */
98 | public function setId(string $id): self
99 | {
100 | $this->adDomElement->setAttribute('id', $id);
101 |
102 | return $this;
103 | }
104 |
105 | /**
106 | * Format a VAST 3.0 response that groups multiple ads into a sequential pod of ads
107 | *
108 | * @param int $sequence a number greater than zero (0) that identifies the sequence in which an ad should play;
109 | * all elements with sequence values are part of a pod and are intended to be played
110 | * in sequence
111 | *
112 | * @return InLine|Wrapper|AbstractAdNode
113 | */
114 | public function setSequence(int $sequence): self
115 | {
116 | $this->adDomElement->setAttribute('sequence', (string)$sequence);
117 |
118 | return $this;
119 | }
120 |
121 | /**
122 | * @return int
123 | */
124 | public function getSequence(): int
125 | {
126 | return (int)($this->adDomElement->getAttribute('sequence'));
127 | }
128 |
129 | /**
130 | * Set /Vast/Ad/Inline/AdSystem element
131 | *
132 | * @param string $adSystem
133 | *
134 | * @return InLine|Wrapper|AbstractAdNode
135 | */
136 | public function setAdSystem(string $adSystem): self
137 | {
138 | $this->setScalarNodeCdata('AdSystem', $adSystem);
139 |
140 | return $this;
141 | }
142 |
143 | /**
144 | * Get /Vast/Ad/Inline/AdSystem element
145 | *
146 | * @return string
147 | */
148 | public function getAdSystem(): string
149 | {
150 | $adSystem = $this->getScalarNodeValue('AdSystem');
151 |
152 | return $adSystem;
153 | }
154 |
155 | /**
156 | * @return string[]
157 | */
158 | abstract protected function getAvailableCreativeTypes(): array;
159 |
160 | /**
161 | * Build object for creative of given type
162 | *
163 | * @param string $type
164 | * @param \DOMElement $creativeDomElement
165 | *
166 | * @return AbstractCreative
167 | */
168 | abstract protected function buildCreativeElement(string $type, \DOMElement $creativeDomElement): AbstractCreative;
169 |
170 | /**
171 | * Create "creative" object of given type
172 | *
173 | * @param string $type
174 | *
175 | * @throws \Exception
176 | *
177 | * @return AbstractCreative
178 | */
179 | final protected function buildCreative(string $type): AbstractCreative
180 | {
181 | // check type
182 | if (!in_array($type, $this->getAvailableCreativeTypes())) {
183 | throw new \InvalidArgumentException(sprintf('Wrong creative specified: %s', $type));
184 | }
185 |
186 | // get container
187 | if (!$this->creativesDomElement) {
188 | // get creatives tag
189 | $this->creativesDomElement = $this->adDomElement->getElementsByTagName('Creatives')->item(0);
190 | if (!$this->creativesDomElement) {
191 | $this->creativesDomElement = $this->adDomElement->ownerDocument->createElement('Creatives');
192 | $this->getDomElement()->appendChild($this->creativesDomElement);
193 | }
194 | }
195 |
196 | // Creative dom element:
197 | $creativeDomElement = $this->creativesDomElement->ownerDocument->createElement('Creative');
198 | $this->creativesDomElement->appendChild($creativeDomElement);
199 |
200 | // Creative type dom element:
201 | $creativeTypeDomElement = $this->adDomElement->ownerDocument->createElement($type);
202 | $creativeDomElement->appendChild($creativeTypeDomElement);
203 |
204 | // object
205 | $creative = $this->buildCreativeElement($type, $creativeDomElement);
206 |
207 | $this->creatives[] = $creative;
208 |
209 | return $creative;
210 | }
211 |
212 | /**
213 | * Add Error tracking url.
214 | * Allowed multiple error elements.
215 | *
216 | * @param string $url
217 | *
218 | * @return AbstractAdNode
219 | */
220 | public function addError(string $url): self
221 | {
222 | $this->addCdataNode('Error', $url);
223 |
224 | return $this;
225 | }
226 |
227 | /**
228 | * Get previously set error tracking url value
229 | *
230 | * @return array
231 | */
232 | public function getErrors(): array
233 | {
234 | return $this->getValuesOfArrayNode('Error');
235 | }
236 |
237 | /**
238 | * Add Impression tracking url
239 | * Allowed multiple impressions
240 | *
241 | * @param string $url A URI that directs the video player to a tracking resource file that the video player
242 | * ust use to notify the ad server when the impression occurs.
243 | * @param string|null $id An ad server id for the impression. Impression URIs of the same id for an ad should
244 | * be requested at the same time or as close in time as possible to help prevent
245 | * discrepancies.
246 | *
247 | * @return AbstractAdNode
248 | */
249 | public function addImpression(string $url, string $id = null): self
250 | {
251 | $attributes = [];
252 | if ($id !== null) {
253 | $attributes['id'] = $id;
254 | }
255 |
256 | $this->addCdataNode(
257 | 'Impression',
258 | $url,
259 | $attributes
260 | );
261 |
262 | return $this;
263 | }
264 |
265 | /**
266 | * Get previously set impression tracking url value
267 | *
268 | * @return array
269 | */
270 | public function getImpressions(): array
271 | {
272 | return $this->getValuesOfArrayNode('Impression');
273 | }
274 |
275 | /**
276 | * Add extension
277 | *
278 | * @param string $type
279 | * @param string $value
280 | *
281 | * @return AbstractAdNode
282 | */
283 | public function addExtension(string $type, string $value): self
284 | {
285 | // get container
286 | if (!$this->extensionsDomElement) {
287 | // get extensions tag
288 | $this->extensionsDomElement = $this->adDomElement->getElementsByTagName('Extensions')->item(0);
289 | if (!$this->extensionsDomElement) {
290 | $this->extensionsDomElement = $this->adDomElement->ownerDocument->createElement('Extensions');
291 | $this->getDomElement()->appendChild($this->extensionsDomElement);
292 | }
293 | }
294 |
295 | // Creative dom element
296 | $extensionDomElement = $this->extensionsDomElement->ownerDocument->createElement('Extension');
297 | $this->extensionsDomElement->appendChild($extensionDomElement);
298 |
299 | // create cdata
300 | $cdata = $this->adDomElement->ownerDocument->createCDATASection($value);
301 |
302 | // append
303 | $extensionDomElement->setAttribute('type', $type);
304 | $extensionDomElement->appendChild($cdata);
305 |
306 | return $this;
307 | }
308 | }
309 |
--------------------------------------------------------------------------------
/src/Ad/InLine.php:
--------------------------------------------------------------------------------
1 |
8 | *
9 | * For the full copyright and license information, please view the LICENSE
10 | * file that was distributed with this source code.
11 | */
12 |
13 | namespace Sokil\Vast\Ad;
14 |
15 | use Sokil\Vast\Creative\AbstractCreative;
16 | use Sokil\Vast\Creative\InLine\Linear as InLineAdLinearCreative;
17 |
18 | class InLine extends AbstractAdNode
19 | {
20 | /**
21 | * @public
22 | */
23 | const TAG_NAME = 'InLine';
24 |
25 | /**
26 | * @private
27 | */
28 | const CREATIVE_TYPE_LINEAR = 'Linear';
29 |
30 | /**
31 | * @return string
32 | */
33 | public function getAdSubElementTagName(): string
34 | {
35 | return self::TAG_NAME;
36 | }
37 |
38 | /**
39 | * Set Ad title
40 | *
41 | * @param string $value
42 | *
43 | * @return InLine
44 | */
45 | public function setAdTitle(string $value): self
46 | {
47 | $this->setScalarNodeCdata('AdTitle', $value);
48 |
49 | return $this;
50 | }
51 |
52 | /**
53 | * Set Ad serving ID
54 | *
55 | * @param string $value
56 | *
57 | * @return InLine
58 | */
59 | public function setAdServingId(string $value): self
60 | {
61 | $this->setScalarNodeCdata('AdServingId', $value);
62 |
63 | return $this;
64 | }
65 |
66 | /**
67 | * Set description
68 | *
69 | * @param string $value
70 | *
71 | * @return InLine
72 | */
73 | public function setDescription(string $value): self
74 | {
75 | $this->setScalarNodeCdata('Description', $value);
76 |
77 | return $this;
78 | }
79 |
80 | /**
81 | * @return string[]
82 | */
83 | protected function getAvailableCreativeTypes(): array
84 | {
85 | return [
86 | self::CREATIVE_TYPE_LINEAR,
87 | ];
88 | }
89 |
90 | /**
91 | * @param string $type
92 | * @param \DOMElement $creativeDomElement
93 | *
94 | * @return AbstractCreative|InLineAdLinearCreative
95 | */
96 | protected function buildCreativeElement(string $type, \DOMElement $creativeDomElement): AbstractCreative
97 | {
98 | switch ($type) {
99 | case self::CREATIVE_TYPE_LINEAR:
100 | $creative = $this->vastElementBuilder->createInLineAdLinearCreative($creativeDomElement);
101 | break;
102 | default:
103 | throw new \RuntimeException(sprintf('Unknown Wrapper creative type %s', $type));
104 | }
105 |
106 | return $creative;
107 | }
108 |
109 | /**
110 | * Create Linear creative
111 | *
112 | * @throws \Exception
113 | *
114 | * @return InLineAdLinearCreative
115 | */
116 | public function createLinearCreative(): InLineAdLinearCreative
117 | {
118 | /** @var InLineAdLinearCreative $creative */
119 | $creative = $this->buildCreative(self::CREATIVE_TYPE_LINEAR);
120 |
121 | return $creative;
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/src/Ad/Wrapper.php:
--------------------------------------------------------------------------------
1 |
8 | *
9 | * For the full copyright and license information, please view the LICENSE
10 | * file that was distributed with this source code.
11 | */
12 |
13 | namespace Sokil\Vast\Ad;
14 |
15 | use Sokil\Vast\Creative\AbstractCreative;
16 | use Sokil\Vast\Creative\Wrapper\Linear as WrapperAdLinearCreative;
17 |
18 | class Wrapper extends AbstractAdNode
19 | {
20 | /**
21 | * @public
22 | */
23 | const TAG_NAME = 'Wrapper';
24 |
25 | /**
26 | * @private
27 | */
28 | const CREATIVE_TYPE_LINEAR = 'Linear';
29 |
30 | /**
31 | * @return string
32 | */
33 | public function getAdSubElementTagName(): string
34 | {
35 | return self::TAG_NAME;
36 | }
37 |
38 | /**
39 | * URI of ad tag of downstream Secondary Ad Server
40 | *
41 | * @param string $uri
42 | *
43 | * @return Wrapper
44 | */
45 | public function setVASTAdTagURI(string $uri): self
46 | {
47 | $this->setScalarNodeCdata('VASTAdTagURI', $uri);
48 |
49 | return $this;
50 | }
51 |
52 | /**
53 | * @return string[]
54 | */
55 | protected function getAvailableCreativeTypes(): array
56 | {
57 | return [
58 | self::CREATIVE_TYPE_LINEAR,
59 | ];
60 | }
61 |
62 | /**
63 | * @param string $type
64 | * @param \DOMElement $creativeDomElement
65 | *
66 | * @return AbstractCreative|WrapperAdLinearCreative
67 | */
68 | protected function buildCreativeElement(string $type, \DOMElement $creativeDomElement): AbstractCreative
69 | {
70 | switch ($type) {
71 | case self::CREATIVE_TYPE_LINEAR:
72 | $creative = $this->vastElementBuilder->createWrapperAdLinearCreative($creativeDomElement);
73 | break;
74 | default:
75 | throw new \RuntimeException(sprintf('Unknown Wrapper creative type %s', $type));
76 | }
77 |
78 | return $creative;
79 | }
80 |
81 | /**
82 | * Create Linear creative
83 | *
84 | * @return WrapperAdLinearCreative
85 | *
86 | * @throws \Exception
87 | */
88 | public function createLinearCreative(): WrapperAdLinearCreative
89 | {
90 | /** @var WrapperAdLinearCreative $creative */
91 | $creative = $this->buildCreative(self::CREATIVE_TYPE_LINEAR);
92 |
93 | return $creative;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/Creative/AbstractCreative.php:
--------------------------------------------------------------------------------
1 |
8 | *
9 | * For the full copyright and license information, please view the LICENSE
10 | * file that was distributed with this source code.
11 | */
12 |
13 | namespace Sokil\Vast\Creative;
14 |
15 | use Sokil\Vast\Document\AbstractNode;
16 |
17 | abstract class AbstractCreative extends AbstractNode
18 | {
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/Creative/AbstractLinearCreative.php:
--------------------------------------------------------------------------------
1 |
8 | *
9 | * For the full copyright and license information, please view the LICENSE
10 | * file that was distributed with this source code.
11 | */
12 |
13 | namespace Sokil\Vast\Creative;
14 |
15 | use Sokil\Vast\ElementBuilder;
16 |
17 | abstract class AbstractLinearCreative extends AbstractCreative
18 | {
19 | /**
20 | * @var ElementBuilder
21 | */
22 | protected $vastElementBuilder;
23 |
24 | /**
25 | * this event should be used to indicate when the player considers that it has loaded
26 | * and buffered the creative’s media and assets either fully or to the extent that it is ready to play the media.
27 | */
28 | public const EVENT_TYPE_LOADED = 'loaded';
29 |
30 | /**
31 | * not to be confused with an impression, this event indicates that an individual creative
32 | * portion of the ad was viewed. An impression indicates the first frame of the ad was displayed; however
33 | * an ad may be composed of multiple creative, or creative that only play on some platforms and not
34 | * others. This event enables ad servers to track which ad creative are viewed, and therefore, which
35 | * platforms are more common.
36 | */
37 | public const EVENT_TYPE_CREATIVEVIEW = 'creativeView';
38 |
39 | /**
40 | * this event is used to indicate that an individual creative within the ad was loaded and playback
41 | * began. As with creativeView, this event is another way of tracking creative playback.
42 | */
43 | public const EVENT_TYPE_START = 'start';
44 |
45 | // the creative played for at least 25% of the total duration.
46 | public const EVENT_TYPE_FIRSTQUARTILE = 'firstQuartile';
47 |
48 | // the creative played for at least 50% of the total duration.
49 | public const EVENT_TYPE_MIDPOINT = 'midpoint';
50 |
51 | // the creative played for at least 75% of the duration.
52 | public const EVENT_TYPE_THIRDQUARTILE = 'thirdQuartile';
53 |
54 | // The creative was played to the end at normal speed.
55 | public const EVENT_TYPE_COMPLETE = 'complete';
56 |
57 | // the user activated the mute control and muted the creative.
58 | public const EVENT_TYPE_MUTE = 'mute';
59 |
60 | // the user activated the mute control and unmuted the creative.
61 | public const EVENT_TYPE_UNMUTE = 'unmute';
62 |
63 | // the user clicked the pause control and stopped the creative.
64 | public const EVENT_TYPE_PAUSE = 'pause';
65 |
66 | // the user activated the rewind control to access a previous point in the creative timeline.
67 | public const EVENT_TYPE_REWIND = 'rewind';
68 |
69 | // the user activated the resume control after the creative had been stopped or paused.
70 | public const EVENT_TYPE_RESUME = 'resume';
71 |
72 | // the user activated a control to extend the video player to the edges of the viewer’s screen.
73 | public const EVENT_TYPE_FULLSCREEN = 'fullscreen';
74 |
75 | // the user activated the control to reduce video player size to original dimensions.
76 | public const EVENT_TYPE_EXITFULLSCREEN = 'exitFullscreen';
77 |
78 | // the user activated a control to expand the creative.
79 | public const EVENT_TYPE_EXPAND = 'expand';
80 |
81 | // the user activated a control to reduce the creative to its original dimensions.
82 | public const EVENT_TYPE_COLLAPSE = 'collapse';
83 |
84 | /**
85 | * The user activated a control that launched an additional portion of the
86 | * creative. The name of this event distinguishes it from the existing “acceptInvitation” event described in
87 | * the 2008 IAB Digital Video In-Stream Ad Metrics Definitions, which defines the “acceptInivitation”
88 | * metric as applying to non-linear ads only. The “acceptInvitationLinear” event extends the metric for use
89 | * in Linear creative.
90 | */
91 | public const EVENT_TYPE_ACCEPTINVITATIONLINEAR = 'acceptInvitationLinear';
92 |
93 | /**
94 | * The user clicked the close button on the creative. The name of this event distinguishes it
95 | * from the existing “close” event described in the 2008 IAB Digital Video In-Stream Ad Metrics
96 | * Definitions, which defines the “close” metric as applying to non-linear ads only. The “closeLinear” event
97 | * extends the “close” event for use in Linear creative.
98 | * Available in VAST v.3, not available in VAST v.4
99 | */
100 | public const EVENT_TYPE_CLOSELINEAR = 'closeLinear';
101 |
102 | // the user activated a skip control to skip the creative, which is a
103 | // different control than the one used to close the creative.
104 | public const EVENT_TYPE_SKIP = 'skip';
105 |
106 | /**
107 | * the creative played for a duration at normal speed that is equal to or greater than the
108 | * value provided in an additional attribute for offset . Offset values can be time in the format
109 | * HH:MM:SS or HH:MM:SS.mmm or a percentage value in the format n% . Multiple progress ev
110 | */
111 | public const EVENT_TYPE_PROGRESS = 'progress';
112 |
113 | /**
114 | * Dom Element of
115 | *
116 | * @var \DOMElement
117 | */
118 | private $linearCreativeDomElement;
119 |
120 | /**
121 | * @var \DOMElement
122 | */
123 | private $videoClicksDomElement;
124 |
125 | /**
126 | * @var \DOMElement
127 | */
128 | private $trackingEventsDomElement;
129 |
130 | /**
131 | * @param \DOMElement $linearCreativeDomElement
132 | * @param ElementBuilder $vastElementBuilder
133 | */
134 | public function __construct(\DOMElement $linearCreativeDomElement, ElementBuilder $vastElementBuilder)
135 | {
136 | $this->linearCreativeDomElement = $linearCreativeDomElement;
137 | $this->vastElementBuilder = $vastElementBuilder;
138 | }
139 |
140 | /**
141 | * Dom Element of
142 | *
143 | * @return \DOMElement
144 | */
145 | protected function getDomElement(): \DOMElement
146 | {
147 | return $this->linearCreativeDomElement;
148 | }
149 |
150 | /**
151 | * List of allowed events
152 | *
153 | * @return array
154 | */
155 | public static function getEventList(): array
156 | {
157 | return [
158 | self::EVENT_TYPE_LOADED,
159 | self::EVENT_TYPE_CREATIVEVIEW,
160 | self::EVENT_TYPE_START,
161 | self::EVENT_TYPE_FIRSTQUARTILE,
162 | self::EVENT_TYPE_MIDPOINT,
163 | self::EVENT_TYPE_THIRDQUARTILE,
164 | self::EVENT_TYPE_COMPLETE,
165 | self::EVENT_TYPE_MUTE,
166 | self::EVENT_TYPE_UNMUTE,
167 | self::EVENT_TYPE_PAUSE,
168 | self::EVENT_TYPE_REWIND,
169 | self::EVENT_TYPE_RESUME,
170 | self::EVENT_TYPE_FULLSCREEN,
171 | self::EVENT_TYPE_EXITFULLSCREEN,
172 | self::EVENT_TYPE_EXPAND,
173 | self::EVENT_TYPE_COLLAPSE,
174 | self::EVENT_TYPE_ACCEPTINVITATIONLINEAR,
175 | self::EVENT_TYPE_CLOSELINEAR,
176 | self::EVENT_TYPE_SKIP,
177 | self::EVENT_TYPE_PROGRESS,
178 | ];
179 | }
180 |
181 | /**
182 | * Get VideoClicks DomElement
183 | *
184 | * @return \DOMElement
185 | */
186 | protected function getVideoClicksDomElement(): \DOMElement
187 | {
188 | // create container
189 | if (!empty($this->videoClicksDomElement)) {
190 | return $this->videoClicksDomElement;
191 | }
192 |
193 | $this->videoClicksDomElement = $this->linearCreativeDomElement->getElementsByTagName('VideoClicks')->item(0);
194 | if (!empty($this->videoClicksDomElement)) {
195 | return $this->videoClicksDomElement;
196 | }
197 |
198 | $this->videoClicksDomElement = $this->linearCreativeDomElement->ownerDocument->createElement('VideoClicks');
199 | $this->linearCreativeDomElement
200 | ->getElementsByTagName('Linear')
201 | ->item(0)
202 | ->appendChild($this->videoClicksDomElement);
203 |
204 | return $this->videoClicksDomElement;
205 | }
206 |
207 | /**
208 | * Add click tracking url
209 | *
210 | * @param string $url
211 | *
212 | * @return AbstractLinearCreative
213 | */
214 | public function addVideoClicksClickTracking(string $url): self
215 | {
216 | // create ClickTracking
217 | $clickTrackingDomElement = $this->getDomElement()->ownerDocument->createElement('ClickTracking');
218 | $this->getVideoClicksDomElement()->appendChild($clickTrackingDomElement);
219 |
220 | // create cdata
221 | $cdata = $this->getDomElement()->ownerDocument->createCDATASection($url);
222 | $clickTrackingDomElement->appendChild($cdata);
223 |
224 | return $this;
225 | }
226 |
227 | /**
228 | * Add custom click url
229 | *
230 | * @param string $url
231 | *
232 | * @return AbstractLinearCreative
233 | */
234 | public function addVideoClicksCustomClick(string $url): self
235 | {
236 | // create CustomClick
237 | $customClickDomElement = $this->getDomElement()->ownerDocument->createElement('CustomClick');
238 | $this->getVideoClicksDomElement()->appendChild($customClickDomElement);
239 |
240 | // create cdata
241 | $cdata = $this->getDomElement()->ownerDocument->createCDATASection($url);
242 | $customClickDomElement->appendChild($cdata);
243 |
244 | return $this;
245 | }
246 |
247 | /**
248 | * Set video click through url
249 | *
250 | * @param string $url
251 | *
252 | * @return AbstractLinearCreative
253 | */
254 | public function setVideoClicksClickThrough(string $url): self
255 | {
256 | // create cdata
257 | $cdata = $this->getDomElement()->ownerDocument->createCDATASection($url);
258 |
259 | // create ClickThrough
260 | $clickThroughDomElement = $this->getVideoClicksDomElement()->getElementsByTagName('ClickThrough')->item(0);
261 | if (!$clickThroughDomElement) {
262 | $clickThroughDomElement = $this->getDomElement()->ownerDocument->createElement('ClickThrough');
263 | $this->getVideoClicksDomElement()->appendChild($clickThroughDomElement);
264 | }
265 |
266 | // update CData
267 | if ($clickThroughDomElement->hasChildNodes()) {
268 | $clickThroughDomElement->replaceChild($cdata, $clickThroughDomElement->firstChild);
269 | } else { // insert CData
270 | $clickThroughDomElement->appendChild($cdata);
271 | }
272 |
273 | return $this;
274 | }
275 |
276 | /**
277 | * Get TrackingEvents DomElement
278 | *
279 | * @return \DOMElement
280 | */
281 | protected function getTrackingEventsDomElement(): \DOMElement
282 | {
283 | // create container
284 | if ($this->trackingEventsDomElement) {
285 | return $this->trackingEventsDomElement;
286 | }
287 |
288 | $this->trackingEventsDomElement = $this->linearCreativeDomElement
289 | ->getElementsByTagName('TrackingEvents')
290 | ->item(0);
291 |
292 | if ($this->trackingEventsDomElement) {
293 | return $this->trackingEventsDomElement;
294 | }
295 |
296 | $this->trackingEventsDomElement = $this->linearCreativeDomElement
297 | ->ownerDocument
298 | ->createElement('TrackingEvents');
299 |
300 | $this->linearCreativeDomElement
301 | ->getElementsByTagName('Linear')
302 | ->item(0)
303 | ->appendChild($this->trackingEventsDomElement);
304 |
305 | return $this->trackingEventsDomElement;
306 | }
307 |
308 | /**
309 | * @param string $event
310 | * @param string $url
311 | *
312 | * @return AbstractLinearCreative
313 | *
314 | * @throws \Exception
315 | */
316 | public function addTrackingEvent(string $event, string $url): self
317 | {
318 | if (!in_array($event, $this->getEventList())) {
319 | throw new \Exception(sprintf('Wrong event "%s" specified', $event));
320 | }
321 |
322 | // create Tracking
323 | $trackingDomElement = $this->linearCreativeDomElement->ownerDocument->createElement('Tracking');
324 | $this->getTrackingEventsDomElement()->appendChild($trackingDomElement);
325 |
326 | // add event attribute
327 | $trackingDomElement->setAttribute('event', $event);
328 |
329 | // create cdata
330 | $cdata = $this->linearCreativeDomElement->ownerDocument->createCDATASection($url);
331 | $trackingDomElement->appendChild($cdata);
332 |
333 | return $this;
334 | }
335 |
336 | /**
337 | * @param string $url
338 | * @param int|string $offset seconds or time in format "H:m:i" or percents in format "n%"
339 | *
340 | * @return AbstractLinearCreative
341 | */
342 | public function addProgressTrackingEvent(string $url, $offset): self
343 | {
344 | // create Tracking
345 | $trackingDomElement = $this->linearCreativeDomElement->ownerDocument->createElement('Tracking');
346 | $this->getTrackingEventsDomElement()->appendChild($trackingDomElement);
347 |
348 | // add event attribute
349 | $trackingDomElement->setAttribute('event', self::EVENT_TYPE_PROGRESS);
350 |
351 | // add offset attribute
352 | if (is_numeric($offset)) {
353 | $offset = $this->secondsToString($offset);
354 | }
355 | $trackingDomElement->setAttribute('offset', $offset);
356 |
357 | // create cdata
358 | $cdata = $this->linearCreativeDomElement->ownerDocument->createCDATASection($url);
359 | $trackingDomElement->appendChild($cdata);
360 |
361 | return $this;
362 | }
363 |
364 | /**
365 | * Convert seconds to H:m:i
366 | * Hours could be more than 24
367 | *
368 | * @param mixed $seconds
369 | *
370 | * @return string
371 | */
372 | protected function secondsToString($seconds)
373 | {
374 | $seconds = (int) $seconds;
375 |
376 | $time = [];
377 |
378 | // get hours
379 | $hours = floor($seconds / 3600);
380 | $time[] = str_pad((string)$hours, 2, '0', STR_PAD_LEFT);
381 |
382 | // get minutes
383 | $seconds = $seconds % 3600;
384 | $time[] = str_pad((string)floor($seconds / 60), 2, '0', STR_PAD_LEFT);
385 |
386 | // get seconds
387 | $time[] = str_pad((string)($seconds % 60), 2, '0', STR_PAD_LEFT);
388 |
389 | return implode(':', $time);
390 | }
391 | }
392 |
--------------------------------------------------------------------------------
/src/Creative/InLine/Linear.php:
--------------------------------------------------------------------------------
1 |
8 | *
9 | * For the full copyright and license information, please view the LICENSE
10 | * file that was distributed with this source code.
11 | */
12 |
13 | namespace Sokil\Vast\Creative\InLine;
14 |
15 | use Sokil\Vast\Creative\AbstractLinearCreative;
16 | use Sokil\Vast\Creative\InLine\Linear\ClosedCaptionFile;
17 | use Sokil\Vast\Creative\InLine\Linear\InteractiveCreativeFile;
18 | use Sokil\Vast\Creative\InLine\Linear\MediaFile;
19 |
20 | class Linear extends AbstractLinearCreative
21 | {
22 | /**
23 | * @var \DOMElement
24 | */
25 | private $mediaFilesDomElement;
26 |
27 | /**
28 | * @var \DOMElement
29 | */
30 | private $closedCaptionFilesDomElement;
31 |
32 | /**
33 | * @var \DOMElement
34 | */
35 | private $adParametersDomElement;
36 |
37 | /**
38 | * Set duration value
39 | *
40 | * @param int|string $duration seconds or time in format "H:m:i"
41 | *
42 | * @return Linear
43 | */
44 | public function setDuration($duration): self
45 | {
46 | // get dom element
47 | $durationDomElement = $this->getDomElement()->getElementsByTagName('Duration')->item(0);
48 | if (!$durationDomElement) {
49 | $durationDomElement = $this->getDomElement()->ownerDocument->createElement('Duration');
50 | $this->getDomElement()->getElementsByTagName('Linear')->item(0)->appendChild($durationDomElement);
51 | }
52 |
53 | // set value
54 | if (is_numeric($duration)) {
55 | // in seconds
56 | $duration = $this->secondsToString($duration);
57 | }
58 |
59 | $durationDomElement->nodeValue = $duration;
60 |
61 | return $this;
62 | }
63 |
64 | /**
65 | * @return \DOMElement
66 | */
67 | private function getMediaFilesElement(): \DOMElement
68 | {
69 | if (empty($this->mediaFilesDomElement)) {
70 | $this->mediaFilesDomElement = $this->getDomElement()->getElementsByTagName('MediaFiles')->item(0);
71 | if (!$this->mediaFilesDomElement) {
72 | $this->mediaFilesDomElement = $this->getDomElement()->ownerDocument->createElement('MediaFiles');
73 | $this->getDomElement()
74 | ->getElementsByTagName('Linear')
75 | ->item(0)
76 | ->appendChild($this->mediaFilesDomElement);
77 | }
78 | }
79 |
80 | return $this->mediaFilesDomElement;
81 | }
82 |
83 | /**
84 | * @return MediaFile
85 | */
86 | public function createMediaFile(): MediaFile
87 | {
88 | // get needed DOM element
89 | $mediaFilesDomElement = $this->getMediaFilesElement();
90 |
91 | // create MediaFile and append to MediaFiles
92 | $mediaFileDomElement = $mediaFilesDomElement->ownerDocument->createElement('MediaFile');
93 | $mediaFilesDomElement->appendChild($mediaFileDomElement);
94 |
95 | // object
96 | return $this->vastElementBuilder->createInLineAdLinearCreativeMediaFile($mediaFileDomElement);
97 | }
98 |
99 | public function createInteractiveCreativeFile(): InteractiveCreativeFile
100 | {
101 | // get needed DOM element
102 | $mediaFilesDomElement = $this->getMediaFilesElement();
103 |
104 | // create MediaFile and append to MediaFiles
105 | $mediaFileDomElement = $mediaFilesDomElement->ownerDocument->createElement('InteractiveCreativeFile');
106 | $mediaFilesDomElement->appendChild($mediaFileDomElement);
107 |
108 | // object
109 | return $this->vastElementBuilder->createInlineAdLinearCreativeInteractiveCreativeMediaFile($mediaFileDomElement);
110 | }
111 |
112 | /**
113 | * @return ClosedCaptionFile
114 | */
115 | public function createClosedCaptionFile(): ClosedCaptionFile
116 | {
117 | //ensure closedCaptionFilesDomElement existence
118 | if (empty($this->closedCaptionFilesDomElement)) {
119 | $mediaFilesElement = $this->getMediaFilesElement();
120 | $this->closedCaptionFilesDomElement = $mediaFilesElement->getElementsByTagName('ClosedCaptionFiles')->item(0);
121 | if (!$this->closedCaptionFilesDomElement) {
122 | $this->closedCaptionFilesDomElement = $this->getDomElement()->ownerDocument->createElement('ClosedCaptionFiles');
123 | $mediaFilesElement->appendChild($this->closedCaptionFilesDomElement);
124 | }
125 | }
126 |
127 | //create closedCaptionFileDomElement and append to closedCaptionFilesDomElement
128 | $closedCaptionFileDomElement = $this->closedCaptionFilesDomElement->ownerDocument->createElement('ClosedCaptionFile');
129 | $this->closedCaptionFilesDomElement->appendChild($closedCaptionFileDomElement);
130 |
131 | return $this->vastElementBuilder->createInLineAdLinearCreativeClosedCaptionFile($closedCaptionFileDomElement);
132 | }
133 |
134 | /**
135 | * @param array|string $params
136 | *
137 | * @return self
138 | */
139 | public function setAdParameters($params): Linear
140 | {
141 | $this->adParametersDomElement = $this->getDomElement()->getElementsByTagName('AdParameters')->item(0);
142 | if (!$this->adParametersDomElement) {
143 | $this->adParametersDomElement = $this->getDomElement()->ownerDocument->createElement('AdParameters');
144 | $this->getDomElement()->getElementsByTagName('Linear')->item(0)->appendChild($this->adParametersDomElement);
145 | }
146 |
147 | if (is_array($params)) {
148 | $params = json_encode($params);
149 | }
150 |
151 | $cdata = $this->adParametersDomElement->ownerDocument->createCDATASection($params);
152 |
153 | // update CData
154 | if ($this->adParametersDomElement->hasChildNodes()) {
155 | $this->adParametersDomElement->replaceChild($cdata, $this->adParametersDomElement->firstChild);
156 | } // insert CData
157 | else {
158 | $this->adParametersDomElement->appendChild($cdata);
159 | }
160 |
161 | return $this;
162 | }
163 |
164 | /**
165 | * @param int|string $time seconds or time in format "H:m:i"
166 | *
167 | * @return Linear
168 | */
169 | public function skipAfter($time): self
170 | {
171 | if (is_numeric($time)) {
172 | $time = $this->secondsToString($time);
173 | }
174 |
175 | $this->getDomElement()->getElementsByTagName('Linear')->item(0)->setAttribute('skipoffset', $time);
176 |
177 | return $this;
178 | }
179 |
180 | /**
181 | * required element for the purpose of tracking ad creative, he added in VAST 4.0 spec.
182 | * Paragraph 3.7.1
183 | * https://iabtechlab.com/wp-content/uploads/2018/11/VAST4.1-final-Nov-8-2018.pdf
184 | *
185 | * @param int|string $idRegistry
186 | * @param int|string $universalAdId
187 | *
188 | * @return Linear
189 | */
190 | public function setUniversalAdId($idRegistry, $universalAdId): self
191 | {
192 | $universalAdIdDomElement = $this->getDomElement()->ownerDocument->createElement('UniversalAdId');
193 | $universalAdIdDomElement->nodeValue = $universalAdId;
194 | $universalAdIdDomElement->setAttribute("idRegistry", $idRegistry);
195 | $this->getDomElement()->insertBefore($universalAdIdDomElement, $this->getDomElement()->firstChild);
196 |
197 | return $this;
198 | }
199 |
200 | /**
201 | * Set 'id' attribute of 'creative' element
202 | *
203 | * @param string $id
204 | *
205 | * @return Linear
206 | */
207 | public function setId(string $id): self
208 | {
209 | $this->getDomElement()->setAttribute('id', $id);
210 |
211 | return $this;
212 | }
213 |
214 | /**
215 | * Set 'adId' attribute of 'creative' element
216 | *
217 | * @param string $adId
218 | *
219 | * @return Linear
220 | */
221 | public function setAdId(string $adId): self
222 | {
223 | $this->getDomElement()->setAttribute('adId', $adId);
224 |
225 | return $this;
226 | }
227 | }
228 |
--------------------------------------------------------------------------------
/src/Creative/InLine/Linear/ClosedCaptionFile.php:
--------------------------------------------------------------------------------
1 |
8 | *
9 | * For the full copyright and license information, please view the LICENSE
10 | * file that was distributed with this source code.
11 | */
12 |
13 | namespace Sokil\Vast\Creative\InLine\Linear;
14 |
15 | /**
16 | * Optional node that enables closed caption sidecar files associated with the ad media (video or audio)
17 | * to be provided to the player. Multiple files with different mime-types may be provided to allow the player
18 | * to select the one it is compatible with.
19 | *
20 | * Compatible with VAST starting from version 4.1
21 | *
22 | * See section 3.9.4 of VAST specification version 4.1
23 | *
24 | * @author Leonardo Matos Rodriguez
25 | */
26 | class ClosedCaptionFile
27 | {
28 | /**
29 | * @var \DomElement
30 | */
31 | private $domElement;
32 |
33 | /**
34 | * @param \DomElement $domElement
35 | */
36 | public function __construct(\DomElement $domElement)
37 | {
38 | $this->domElement = $domElement;
39 | }
40 |
41 | /**
42 | * Set file mime type
43 | *
44 | * @param string $mime Mime type of the file
45 | */
46 | public function setType(string $mime): self
47 | {
48 | $this->domElement->setAttribute('type', $mime);
49 |
50 | return $this;
51 | }
52 |
53 | /**
54 | * Set file language
55 | *
56 | * @param string $languag Language of the file e.g: 'en'
57 | */
58 | public function setLanguage(string $language): self
59 | {
60 | $this->domElement->setAttribute('language', $language);
61 |
62 | return $this;
63 | }
64 |
65 | /**
66 | * Set file URL
67 | *
68 | * @param string $url URL of the file
69 | */
70 | public function setUrl(string $url): self
71 | {
72 | $cdata = $this->domElement->ownerDocument->createCDATASection($url);
73 |
74 | // update CData
75 | if ($this->domElement->hasChildNodes()) {
76 | $this->domElement->replaceChild($cdata, $this->domElement->firstChild);
77 | } // insert CData
78 | else {
79 | $this->domElement->appendChild($cdata);
80 | }
81 | return $this;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/Creative/InLine/Linear/InteractiveCreativeFile.php:
--------------------------------------------------------------------------------
1 |
8 | *
9 | * For the full copyright and license information, please view the LICENSE
10 | * file that was distributed with this source code.
11 | */
12 |
13 | namespace Sokil\Vast\Creative\InLine\Linear;
14 |
15 | /**
16 | * Optional node that enables interactive creative files associated with the ad media (video or audio)
17 | * to be provided to the player.
18 | *
19 | * Compatible with VAST starting from version 4.0
20 | *
21 | * See section 3.9.3 of VAST specification version 4.1
22 | *
23 | * @author Bram Devries
24 | */
25 | class InteractiveCreativeFile
26 | {
27 | /**
28 | * @var \DomElement
29 | */
30 | private $domElement;
31 |
32 | /**
33 | * @param \DomElement $domElement
34 | */
35 | public function __construct(\DomElement $domElement)
36 | {
37 | $this->domElement = $domElement;
38 | }
39 |
40 | /**
41 | * Set file mime type
42 | *
43 | * @param string $mime Mime type of the file
44 | */
45 | public function setType(string $mime): self
46 | {
47 | $this->domElement->setAttribute('type', $mime);
48 |
49 | return $this;
50 | }
51 |
52 | /**
53 | * @param string $apiFramework the API needed to execute the resource file if applicable.
54 | */
55 | public function setApiFramework(string $apiFramework): self
56 | {
57 | $this->domElement->setAttribute('apiFramework', $apiFramework);
58 |
59 | return $this;
60 | }
61 |
62 | /**
63 | * Set file URL
64 | *
65 | * @param string $url URL of the file
66 | */
67 | public function setUrl(string $url): self
68 | {
69 | $cdata = $this->domElement->ownerDocument->createCDATASection($url);
70 |
71 | // update CData
72 | if ($this->domElement->hasChildNodes()) {
73 | $this->domElement->replaceChild($cdata, $this->domElement->firstChild);
74 | } // insert CData
75 | else {
76 | $this->domElement->appendChild($cdata);
77 | }
78 | return $this;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/Creative/InLine/Linear/MediaFile.php:
--------------------------------------------------------------------------------
1 |
8 | *
9 | * For the full copyright and license information, please view the LICENSE
10 | * file that was distributed with this source code.
11 | */
12 |
13 | namespace Sokil\Vast\Creative\InLine\Linear;
14 |
15 | class MediaFile
16 | {
17 | public const DELIVERY_PROGRESSIVE = 'progressive';
18 | public const DELIVERY_STREAMING = 'streaming';
19 |
20 | /**
21 | * @var \DomElement
22 | */
23 | private $domElement;
24 |
25 | /**
26 | * @param \DomElement $domElement
27 | */
28 | public function __construct(\DomElement $domElement)
29 | {
30 | $this->domElement = $domElement;
31 | }
32 |
33 | /**
34 | * @return MediaFile
35 | */
36 | public function setProgressiveDelivery(): self
37 | {
38 | $this->setDelivery(self::DELIVERY_PROGRESSIVE);
39 |
40 | return $this;
41 | }
42 |
43 | /**
44 | * @return MediaFile
45 | */
46 | public function setStreamingDelivery(): self
47 | {
48 | $this->setDelivery(self::DELIVERY_STREAMING);
49 |
50 | return $this;
51 | }
52 |
53 | /**
54 | * Either “progressive” for progressive download protocols (such as HTTP) or “streaming” for streaming protocols
55 | *
56 | * @param string $delivery One of MediaFile::DELIVERY_ constants
57 | *
58 | * @return MediaFile
59 | *
60 | * @throws \InvalidArgumentException
61 | */
62 | public function setDelivery(string $delivery): self
63 | {
64 | if (!in_array($delivery, [self::DELIVERY_PROGRESSIVE, self::DELIVERY_STREAMING])) {
65 | throw new \InvalidArgumentException('Wrong delivery specified');
66 | }
67 |
68 | $this->domElement->setAttribute('delivery', $delivery);
69 |
70 | return $this;
71 | }
72 |
73 | /**
74 | * MIME type for the file container. Popular MIME types include, but are not
75 | * limited to “video/mp4” for MP4, “audio/mpeg” and "audio/aac" for audio ads.
76 | *
77 | * @param string $mime
78 | *
79 | * @return MediaFile
80 | */
81 | public function setType(string $mime): self
82 | {
83 | $this->domElement->setAttribute('type', $mime);
84 | return $this;
85 | }
86 |
87 | /**
88 | * The native width of the video file, in pixels. (0 for audio ads)
89 | *
90 | * @param int $width
91 | *
92 | * @return MediaFile
93 | */
94 | public function setWidth(int $width): self
95 | {
96 | $this->domElement->setAttribute('width', (string)$width);
97 |
98 | return $this;
99 | }
100 |
101 | /**
102 | * The native height of the video file, in pixels. (0 for audio ads)
103 | *
104 | * @param int $height
105 | *
106 | * @return MediaFile
107 | */
108 | public function setHeight(int $height): self
109 | {
110 | $this->domElement->setAttribute('height', (string)$height);
111 |
112 | return $this;
113 | }
114 |
115 | /**
116 | * @param string $url
117 | *
118 | * @return MediaFile
119 | */
120 | public function setUrl(string $url): self
121 | {
122 | $cdata = $this->domElement->ownerDocument->createCDATASection($url);
123 |
124 | // update CData
125 | if ($this->domElement->hasChildNodes()) {
126 | $this->domElement->replaceChild($cdata, $this->domElement->firstChild);
127 | } // insert CData
128 | else {
129 | $this->domElement->appendChild($cdata);
130 | }
131 | return $this;
132 | }
133 |
134 | /**
135 | * @param int $bitrate
136 | *
137 | * @return $this
138 | */
139 | public function setBitrate(int $bitrate): self
140 | {
141 | $this->domElement->setAttribute('bitrate', (string)$bitrate);
142 |
143 | return $this;
144 | }
145 |
146 | /**
147 | * @deprecated Please note that this attribute is deprecated since VAST 4.1 along with VPAID
148 | *
149 | * Identifies the API needed to execute an interactive media file, but current support is for backward
150 | * compatibility. Please use the element to include files that
151 | * require an API for execution.
152 | *
153 | * @param string $value
154 | *
155 | * @return $this
156 | */
157 | public function setApiFramework(string $value): self
158 | {
159 | $this->domElement->setAttribute('apiFramework', (string) $value);
160 |
161 | return $this;
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/src/Creative/Wrapper/Linear.php:
--------------------------------------------------------------------------------
1 |
8 | *
9 | * For the full copyright and license information, please view the LICENSE
10 | * file that was distributed with this source code.
11 | */
12 |
13 | namespace Sokil\Vast\Creative\Wrapper;
14 |
15 | use Sokil\Vast\Creative\AbstractLinearCreative;
16 |
17 | class Linear extends AbstractLinearCreative
18 | {
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/Document.php:
--------------------------------------------------------------------------------
1 |
8 | *
9 | * For the full copyright and license information, please view the LICENSE
10 | * file that was distributed with this source code.
11 | */
12 |
13 | namespace Sokil\Vast;
14 |
15 | use Sokil\Vast\Ad\AbstractAdNode;
16 | use Sokil\Vast\Ad\InLine;
17 | use Sokil\Vast\Ad\Wrapper;
18 | use Sokil\Vast\Document\AbstractNode;
19 |
20 | class Document extends AbstractNode
21 | {
22 | /**
23 | * @var \DOMDocument
24 | */
25 | private $domDocument;
26 |
27 | /**
28 | * @var ElementBuilder
29 | */
30 | private $vastElementBuilder;
31 |
32 | /**
33 | * Ad node list
34 | *
35 | * @var AbstractAdNode[]
36 | */
37 | private $vastAdNodeList = [];
38 |
39 | /**
40 | * @param \DOMDocument $DOMDocument
41 | */
42 | public function __construct(\DOMDocument $DOMDocument, ElementBuilder $vastElementBuilder)
43 | {
44 | $this->domDocument = $DOMDocument;
45 | $this->vastElementBuilder = $vastElementBuilder;
46 | }
47 |
48 | /**
49 | * @return \DOMElement
50 | */
51 | protected function getDomElement(): \DOMElement
52 | {
53 | return $this->domDocument->documentElement;
54 | }
55 |
56 | /**
57 | * "Magic" method to convert document to string
58 | *
59 | * @return string
60 | */
61 | public function __toString()
62 | {
63 | return $this->domDocument->saveXML();
64 | }
65 |
66 | /**
67 | * Get DomDocument object
68 | *
69 | * @return \DomDocument
70 | */
71 | public function toDomDocument(): \DOMDocument
72 | {
73 | return $this->domDocument;
74 | }
75 |
76 | /**
77 | * Create "Ad" section on "VAST" node
78 | *
79 | * @param string $type
80 | *
81 | * @throws \InvalidArgumentException
82 | *
83 | * @return AbstractAdNode|InLine|Wrapper
84 | */
85 | private function createAdSection($type): AbstractAdNode
86 | {
87 | // Check Ad type
88 | if (!in_array($type, [InLine::TAG_NAME, Wrapper::TAG_NAME])) {
89 | throw new \InvalidArgumentException(sprintf('Ad type %s not supported', $type));
90 | }
91 |
92 | // create dom node
93 | $adDomElement = $this->domDocument->createElement('Ad');
94 | $this->domDocument->documentElement->appendChild($adDomElement);
95 |
96 | // create type element
97 | $adTypeDomElement = $this->domDocument->createElement($type);
98 | $adDomElement->appendChild($adTypeDomElement);
99 |
100 | // create ad section
101 | switch ($type) {
102 | case InLine::TAG_NAME:
103 | $adSection = $this->vastElementBuilder->createInLineAdNode($adDomElement);
104 | break;
105 | case Wrapper::TAG_NAME:
106 | $adSection = $this->vastElementBuilder->createWrapperAdNode($adDomElement);
107 | break;
108 | default:
109 | throw new \InvalidArgumentException(sprintf('Ad type %s not supported', $type));
110 | }
111 |
112 | // cache
113 | $this->vastAdNodeList[] = $adSection;
114 |
115 | return $adSection;
116 | }
117 |
118 | /**
119 | * Create inline Ad section
120 | *
121 | * @return \Sokil\Vast\Ad\InLine
122 | */
123 | public function createInLineAdSection(): InLine
124 | {
125 | return $this->createAdSection(InLine::TAG_NAME);
126 | }
127 |
128 | /**
129 | * Create Wrapper Ad section
130 | *
131 | * @return \Sokil\Vast\Ad\Wrapper
132 | */
133 | public function createWrapperAdSection(): Wrapper
134 | {
135 | return $this->createAdSection(Wrapper::TAG_NAME);
136 | }
137 |
138 | /**
139 | * Get document ad sections
140 | *
141 | * @return AbstractAdNode[]
142 | *
143 | * @throws \Exception
144 | */
145 | public function getAdSections(): array
146 | {
147 | if (!empty($this->vastAdNodeList)) {
148 | return $this->vastAdNodeList;
149 | }
150 |
151 | foreach ($this->domDocument->documentElement->childNodes as $adDomElement) {
152 | // get Ad tag
153 | if (!$adDomElement instanceof \DOMElement) {
154 | continue;
155 | }
156 |
157 | if ('ad' !== strtolower($adDomElement->tagName)) {
158 | continue;
159 | }
160 |
161 | // get Ad type tag
162 | foreach ($adDomElement->childNodes as $node) {
163 | if (!($node instanceof \DOMElement)) {
164 | continue;
165 | }
166 |
167 | $type = $node->tagName;
168 |
169 | // create ad section
170 | switch ($type) {
171 | case InLine::TAG_NAME:
172 | $adSection = $this->vastElementBuilder->createInLineAdNode($adDomElement);
173 | break;
174 | case Wrapper::TAG_NAME:
175 | $adSection = $this->vastElementBuilder->createWrapperAdNode($adDomElement);
176 | break;
177 | default:
178 | throw new \Exception('Ad type ' . $type . ' not supported');
179 | }
180 |
181 | $this->vastAdNodeList[] = $adSection;
182 | }
183 | }
184 |
185 | return $this->vastAdNodeList;
186 | }
187 |
188 | /**
189 | * Add Error tracking url.
190 | * Allowed multiple error elements.
191 | *
192 | * @param string $url
193 | *
194 | * @return Document
195 | */
196 | public function addErrors(string $url): self
197 | {
198 | $this->addCdataNode('Error', $url);
199 | return $this;
200 | }
201 |
202 | /**
203 | * Get previously set error tracking url value
204 | *
205 | * @return array
206 | */
207 | public function getErrors(): array
208 | {
209 | return $this->getValuesOfArrayNode('Error');
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/src/Document/AbstractNode.php:
--------------------------------------------------------------------------------
1 |
8 | *
9 | * For the full copyright and license information, please view the LICENSE
10 | * file that was distributed with this source code.
11 | */
12 |
13 | namespace Sokil\Vast\Document;
14 |
15 | abstract class AbstractNode
16 | {
17 | /**
18 | * Root DOM element, represented by this Node class.
19 | *
20 | * @return \DOMElement
21 | */
22 | abstract protected function getDomElement(): \DOMElement;
23 |
24 | /**
25 | * Set cdata for given child node or create new child node
26 | *
27 | * @param string $name name of node
28 | * @param string $value value of cdata
29 | *
30 | * @return AbstractNode
31 | */
32 | protected function setScalarNodeCdata($name, $value): self
33 | {
34 | // get tag
35 | $childDomElement = $this->getDomElement()->getElementsByTagName($name)->item(0);
36 | if ($childDomElement === null) {
37 | $childDomElement = $this->getDomElement()->ownerDocument->createElement($name);
38 | $this->getDomElement()->appendChild($childDomElement);
39 | }
40 |
41 | // upsert cdata
42 | $cdata = $this->getDomElement()->ownerDocument->createCDATASection($value);
43 | if ($childDomElement->hasChildNodes()) {
44 | // update cdata
45 | $childDomElement->replaceChild($cdata, $childDomElement->firstChild);
46 | } else {
47 | // insert cdata
48 | $childDomElement->appendChild($cdata);
49 | }
50 |
51 | return $this;
52 | }
53 |
54 | /**
55 | * @param string $name
56 | *
57 | * @return string
58 | *
59 | * @throws \InvalidArgumentException when node not found
60 | */
61 | protected function getScalarNodeValue(string $name): string
62 | {
63 | $domElements = $this->getDomElement()->getElementsByTagName($name);
64 | if ($domElements->length === 0) {
65 | throw new \InvalidArgumentException(sprintf('Unknown scalar node %s', $name));
66 | }
67 |
68 | return $domElements->item(0)->nodeValue;
69 | }
70 |
71 | /**
72 | * Append new child node to node
73 | *
74 | * @param string $nodeName
75 | * @param string $value
76 | * @param array $attributes
77 | *
78 | * @return AbstractNode
79 | */
80 | protected function addCdataNode($nodeName, $value, array $attributes = []): self
81 | {
82 | // create element
83 | $domElement = $this->getDomElement()->ownerDocument->createElement($nodeName);
84 | $this->getDomElement()->appendChild($domElement);
85 |
86 | // create cdata
87 | $cdata = $this->getDomElement()->ownerDocument->createCDATASection($value);
88 | $domElement->appendChild($cdata);
89 |
90 | // add attributes
91 | foreach ($attributes as $attributeId => $attributeValue) {
92 | $domElement->setAttribute($attributeId, $attributeValue);
93 | }
94 |
95 | return $this;
96 | }
97 |
98 | /**
99 | * @param string $nodeName
100 | *
101 | * @return string[]
102 | */
103 | protected function getValuesOfArrayNode(string $nodeName): array
104 | {
105 | $domElements = $this->getDomElement()->getElementsByTagName($nodeName);
106 |
107 | $values = [];
108 | for ($i = 0; $i < $domElements->length; $i++) {
109 | $values[$i] = $domElements->item($i)->nodeValue;
110 | }
111 |
112 | return $values;
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/src/ElementBuilder.php:
--------------------------------------------------------------------------------
1 |
8 | *
9 | * For the full copyright and license information, please view the LICENSE
10 | * file that was distributed with this source code.
11 | */
12 |
13 | namespace Sokil\Vast;
14 |
15 | use Sokil\Vast\Ad\InLine;
16 | use Sokil\Vast\Ad\Wrapper;
17 | use Sokil\Vast\Creative\InLine\Linear as InLineAdLinearCreative;
18 | use Sokil\Vast\Creative\InLine\Linear\InteractiveCreativeFile;
19 | use Sokil\Vast\Creative\Wrapper\Linear as WrapperAdLinearCreative;
20 | use Sokil\Vast\Creative\InLine\Linear\MediaFile;
21 | use Sokil\Vast\Creative\InLine\Linear\ClosedCaptionFile;
22 |
23 | /**
24 | * Builder of VAST document elements, useful for overriding element classes
25 | */
26 | class ElementBuilder
27 | {
28 | /**
29 | * with inside
30 | *
31 | * @param \DomDocument $xmlDocument
32 | *
33 | * @return Document
34 | */
35 | public function createDocument(\DomDocument $xmlDocument): Document
36 | {
37 | return new Document(
38 | $xmlDocument,
39 | $this
40 | );
41 | }
42 |
43 | /**
44 | * with inside
45 | *
46 | * @param \DomElement $adElement
47 | *
48 | * @return InLine
49 | */
50 | public function createInLineAdNode(\DomElement $adElement): InLine
51 | {
52 | return new InLine($adElement, $this);
53 | }
54 |
55 | /**
56 | * with inside
57 | *
58 | * @param \DomElement $adElement
59 | *
60 | * @return Wrapper
61 | */
62 | public function createWrapperAdNode(\DomElement $adElement): Wrapper
63 | {
64 | return new Wrapper($adElement, $this);
65 | }
66 |
67 | /**
68 | * with inside
69 | *
70 | * @param \DOMElement $creativeDomElement
71 | *
72 | * @return InLineAdLinearCreative
73 | */
74 | public function createInLineAdLinearCreative(\DOMElement $creativeDomElement): InLineAdLinearCreative
75 | {
76 | return new InLineAdLinearCreative($creativeDomElement, $this);
77 | }
78 |
79 | /**
80 | * with inside
81 | *
82 | * @param \DOMElement $creativeDomElement
83 | *
84 | * @return WrapperAdLinearCreative
85 | */
86 | public function createWrapperAdLinearCreative(\DOMElement $creativeDomElement): WrapperAdLinearCreative
87 | {
88 | return new WrapperAdLinearCreative($creativeDomElement, $this);
89 | }
90 |
91 | /**
92 | *
93 | *
94 | * @param \DOMElement $mediaFileDomElement
95 | *
96 | * @return MediaFile
97 | */
98 | public function createInLineAdLinearCreativeMediaFile(\DOMElement $mediaFileDomElement): MediaFile
99 | {
100 | return new MediaFile($mediaFileDomElement);
101 | }
102 |
103 | /**
104 | *
105 | *
106 | * @param \DOMElement $mediaFileDomElement
107 | *
108 | * @return InteractiveCreativeFile
109 | */
110 | public function createInlineAdLinearCreativeInteractiveCreativeMediaFile(\DOMElement $mediaFileDomElement): InteractiveCreativeFile
111 | {
112 | return new InteractiveCreativeFile($mediaFileDomElement);
113 | }
114 |
115 | /**
116 | *
117 | *
118 | * @param \DOMElement $mediaFileDomElement
119 | *
120 | * @return ClosedCaptionFile
121 | */
122 | public function createInLineAdLinearCreativeClosedCaptionFile(\DOMElement $mediaFileDomElement): ClosedCaptionFile
123 | {
124 | return new ClosedCaptionFile($mediaFileDomElement);
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/src/Factory.php:
--------------------------------------------------------------------------------
1 |
8 | *
9 | * For the full copyright and license information, please view the LICENSE
10 | * file that was distributed with this source code.
11 | */
12 |
13 | namespace Sokil\Vast;
14 |
15 | class Factory
16 | {
17 | /**
18 | * @var ElementBuilder
19 | */
20 | private $vastElementBuilder;
21 |
22 | /**
23 | * @param ElementBuilder $vastElementBuilder
24 | */
25 | public function __construct(ElementBuilder $vastElementBuilder = null)
26 | {
27 | if ($vastElementBuilder === null) {
28 | $vastElementBuilder = new ElementBuilder();
29 | }
30 |
31 | $this->vastElementBuilder = $vastElementBuilder;
32 | }
33 |
34 | /**
35 | * Create new VAST document
36 | *
37 | * @param string $vastVersion
38 | *
39 | * @return Document
40 | */
41 | public function create(string $vastVersion = '2.0'): Document
42 | {
43 | $xml = $this->createDomDocument();
44 |
45 | // root
46 | $root = $xml->createElement('VAST');
47 | $xml->appendChild($root);
48 |
49 | // version
50 | $vastVersionAttribute = $xml->createAttribute('version');
51 | $vastVersionAttribute->value = $vastVersion;
52 | $root->appendChild($vastVersionAttribute);
53 |
54 | // return
55 | return $this->vastElementBuilder->createDocument($xml);
56 | }
57 |
58 | /**
59 | * Create VAST document from file
60 | *
61 | * @param string $filename
62 | *
63 | * @return Document
64 | */
65 | public function fromFile(string $filename): Document
66 | {
67 | $xml = $this->createDomDocument();
68 | $xml->load($filename);
69 |
70 | return $this->vastElementBuilder->createDocument($xml);
71 | }
72 |
73 | /**
74 | * Create VAST document from given string with xml
75 | *
76 | * @param string $xmlString
77 | *
78 | * @return Document
79 | */
80 | public function fromString(string $xmlString): Document
81 | {
82 | $xml = $this->createDomDocument();
83 | $xml->loadXml($xmlString);
84 |
85 | return $this->vastElementBuilder->createDocument($xml);
86 | }
87 |
88 | /**
89 | * Create dom document
90 | *
91 | * @return \DomDocument
92 | */
93 | private function createDomDocument(): \DOMDocument
94 | {
95 | return new \DomDocument('1.0', 'UTF-8');
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/tests/.phpunit.cache/test-results:
--------------------------------------------------------------------------------
1 | {"version":1,"defects":[],"times":{"Sokil\\Vast\\DocumentTest::testCreateInLineAdSection":0.006,"Sokil\\Vast\\DocumentTest::testReplaceVideoClicksClickThrough":0,"Sokil\\Vast\\DocumentTest::testGetAdSection":0.001,"Sokil\\Vast\\DocumentTest::testCreateLinearCreativeWithSkipAfter":0,"Sokil\\Vast\\DocumentTest::testCreateLinearCreativeWithStreamingDelivery":0,"Sokil\\Vast\\DocumentTest::testCreateLinearCreativeWithClosedCaptions":0.001,"Sokil\\Vast\\DocumentTest::testCreateLinearCreativeWithClosedCaptionsAndMedia":0,"Sokil\\Vast\\DocumentTest::testCreateLinearCreativeWithInteractiveCreativeFileAndMedia":0.001,"Sokil\\Vast\\DocumentTest::testCreateAdSectionWithDelivery":0,"Sokil\\Vast\\DocumentTest::testCreateAdSectionWithInvalidDelivery":0,"Sokil\\Vast\\DocumentTest::testCreateAdSectionWithAddingExtension":0.001,"Sokil\\Vast\\DocumentTest::testCreateAdSectionWithSettingSequence":0,"Sokil\\Vast\\DocumentTest::testCreateWrapperAdSection":0.001,"Sokil\\Vast\\DocumentTest::testErrorInDocument":0,"Sokil\\Vast\\DocumentTest::testErrorInWrapperAd":0,"Sokil\\Vast\\DocumentTest::testErrorInInlineAd":0,"Sokil\\Vast\\DocumentTest::testImpressionInWrapperAd":0,"Sokil\\Vast\\DocumentTest::testToString":0,"Sokil\\Vast\\DocumentTest::testToDomDocument":0,"Sokil\\Vast\\DocumentTest::testCreate":0,"Sokil\\Vast\\DocumentTest::testFromString":0,"Sokil\\Vast\\DocumentTest::testFromFile":0,"Sokil\\Vast\\DocumentTest::testVpaidCreative":0,"Sokil\\Vast\\ElementBuilderTest::testCustomAttributes":0.002,"Sokil\\Vast\\FactoryTest::testFromFile":0,"Sokil\\Vast\\FactoryTest::testFromString":0}}
--------------------------------------------------------------------------------
/tests/AbstractTestCase.php:
--------------------------------------------------------------------------------
1 | assertXmlStringEqualsXmlFile(
24 | $this->getFullXMLFixturePath($expectedXmlFixturePath),
25 | (string)$actualXmlDomDocument
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/DocumentTest.php:
--------------------------------------------------------------------------------
1 | create('4.1');
16 | $this->assertInstanceOf('\\Sokil\\Vast\\Document', $document);
17 |
18 | // insert Ad section
19 | $ad1 = $document
20 | ->createInLineAdSection()
21 | ->setId('ad1')
22 | ->setAdSystem('Ad Server Name')
23 | ->setAdTitle('Ad Title')
24 | ->setAdServingId('my-ad-server-id')
25 | ->setDescription('Ad Description')
26 | ->addImpression('http://ad.server.com/impression', 'imp1');
27 |
28 | // create creative for ad section
29 | $ad1
30 | ->createLinearCreative()
31 | ->setDuration(128)
32 | ->setId('013d876d-14fc-49a2-aefd-744fce68365b')
33 | ->setAdId('pre')
34 | ->setUniversalAdId('ad-server.com', '15051996')
35 | ->setVideoClicksClickThrough('http://entertainmentserver.com/landing')
36 | ->addVideoClicksClickTracking('http://ad.server.com/videoclicks/clicktracking')
37 | ->addVideoClicksCustomClick('http://ad.server.com/videoclicks/customclick')
38 | ->addTrackingEvent('start', 'http://ad.server.com/trackingevent/start')
39 | ->addTrackingEvent('pause', 'http://ad.server.com/trackingevent/stop')
40 | ->addProgressTrackingEvent('http://ad.server.com/trackingevent/progress', 10)
41 | ->createMediaFile()
42 | ->setProgressiveDelivery()
43 | ->setType('video/mp4')
44 | ->setHeight(100)
45 | ->setWidth(100)
46 | ->setBitrate(600)
47 | ->setUrl('http://server.com/media.mp4');
48 |
49 | $this->assertVastDocumentSameWithXmlFixture('inlineAd.xml', $document);
50 | }
51 |
52 | /**
53 | * Test for inline ad
54 | */
55 | public function testReplaceVideoClicksClickThrough()
56 | {
57 | $factory = new Factory();
58 | $document = $factory->create('2.0');
59 |
60 | // insert Ad section
61 | $ad1 = $document->createInLineAdSection();
62 |
63 | // create creative for ad section
64 | $ad1->createLinearCreative()
65 | ->setVideoClicksClickThrough('http://entertainmentserver.com/landing1')
66 | ->setVideoClicksClickThrough('http://entertainmentserver.com/landing2');
67 |
68 | $this->assertVastDocumentSameWithXmlFixture(
69 | 'replacedClickThrough.xml',
70 | $document
71 | );
72 | }
73 |
74 | /**
75 | * Test for inline ad
76 | */
77 | public function testGetAdSection()
78 | {
79 | $factory = new Factory();
80 | $document = $factory->create('2.0');
81 | $this->assertInstanceOf('\Sokil\Vast\Document', $document);
82 |
83 | // insert Ad section
84 | $ad1 = $document
85 | ->createInLineAdSection()
86 | ->setId('ad1')
87 | ->setAdSystem('Ad Server Name')
88 | ->setAdTitle('Ad Title')
89 | ->addImpression('http://ad.server.com/impression');
90 |
91 | // create creative for ad section
92 | $ad1
93 | ->createLinearCreative()
94 | ->setDuration(128)
95 | ->setVideoClicksClickThrough('http://entertainmentserver.com/landing')
96 | ->addVideoClicksClickTracking('http://ad.server.com/videoclicks/clicktracking')
97 | ->addVideoClicksCustomClick('http://ad.server.com/videoclicks/customclick')
98 | ->addTrackingEvent('start', 'http://ad.server.com/trackingevent/start')
99 | ->addTrackingEvent('pause', 'http://ad.server.com/trackingevent/stop')
100 | ->createMediaFile()
101 | ->setProgressiveDelivery()
102 | ->setType('video/mp4')
103 | ->setHeight(100)
104 | ->setWidth(100)
105 | ->setUrl('http://server.com/media.mp4');
106 |
107 | $adSections = $document->getAdSections();
108 | $this->assertCount(1, $adSections);
109 |
110 | /** @var InLine $adSection */
111 | $adSection = $adSections[0];
112 | $this->assertInstanceOf('\\Sokil\\Vast\\Ad\\InLine', $adSection);
113 |
114 | $this->assertSame('ad1', $adSection->getId());
115 | }
116 |
117 | /**
118 | * Test for creating media file with skipping after specific time
119 | */
120 | public function testCreateLinearCreativeWithSkipAfter()
121 | {
122 | $factory = new Factory();
123 | $document = $factory->create('2.0');
124 |
125 | // insert Ad section
126 | $ad1 = $document
127 | ->createInLineAdSection()
128 | ->setId('ad1')
129 | ->setAdSystem('Ad Server Name')
130 | ->setAdTitle('Ad Title')
131 | ->addImpression('http://ad.server.com/impression');
132 |
133 | $ad1
134 | ->createLinearCreative()
135 | ->skipAfter(1519203721);
136 |
137 | $this->assertVastDocumentSameWithXmlFixture('linearCreativeWithSkipAfter.xml', $document);
138 | }
139 |
140 | /**
141 | * Test for creating media file with streaming delivery
142 | */
143 | public function testCreateLinearCreativeWithStreamingDelivery()
144 | {
145 | $factory = new Factory();
146 | $document = $factory->create('2.0');
147 |
148 | // insert Ad section
149 | $ad1 = $document
150 | ->createInLineAdSection()
151 | ->setId('ad1')
152 | ->setAdSystem('Ad Server Name')
153 | ->setAdTitle('Ad Title')
154 | ->addImpression('http://ad.server.com/impression');
155 | $ad1->createLinearCreative()->createMediaFile()->setStreamingDelivery();
156 |
157 | $this->assertVastDocumentSameWithXmlFixture('linearCreativeWithStreamingDelivery.xml', $document);
158 | }
159 |
160 | /**
161 | * Test for creating media file with Closed Captions
162 | */
163 | public function testCreateLinearCreativeWithClosedCaptions()
164 | {
165 | $factory = new Factory();
166 | $document = $factory->create('4.1');
167 |
168 | // insert Ad section
169 | $ad1 = $document
170 | ->createInLineAdSection()
171 | ->setId('ad1')
172 | ->setAdSystem('Ad Server Name')
173 | ->setAdTitle('Ad Title')
174 | ->addImpression('http://ad.server.com/impression');
175 | $ad1
176 | ->createLinearCreative()
177 | ->createClosedCaptionFile()
178 | ->setLanguage('en')
179 | ->setType('text/srt')
180 | ->setUrl('http://http://example.com/test.srt');
181 |
182 | $this->assertVastDocumentSameWithXmlFixture('linearCreativeWithClosedCaption.xml', $document);
183 | }
184 |
185 | /**
186 | * Test for creating media file with Closed Captions and Media Files
187 | */
188 | public function testCreateLinearCreativeWithClosedCaptionsAndMedia()
189 | {
190 | $factory = new Factory();
191 | $document = $factory->create('4.1');
192 |
193 | // insert Ad section
194 | $ad1 = $document
195 | ->createInLineAdSection()
196 | ->setId('ad1')
197 | ->setAdSystem('Ad Server Name')
198 | ->setAdTitle('Ad Title')
199 | ->addImpression('http://ad.server.com/impression');
200 |
201 | $linear = $ad1->createLinearCreative();
202 |
203 | $linear
204 | ->createClosedCaptionFile()
205 | ->setLanguage('en')
206 | ->setType('text/srt')
207 | ->setUrl('http://example.com/test.srt');
208 |
209 | $linear
210 | ->createClosedCaptionFile()
211 | ->setLanguage('es-DO')
212 | ->setType('text/vtt')
213 | ->setUrl('http://example.com/closedcaption.vtt')
214 | ->setUrl('http://example.com/closedcaption2.vtt');
215 |
216 | $linear->createMediaFile()->setStreamingDelivery();
217 |
218 | $this->assertVastDocumentSameWithXmlFixture('linearCreativeWithClosedCaptionAndMediaFile.xml', $document);
219 | }
220 |
221 | /**
222 | * Test for creating media file with Interactive Creative and Media Files
223 | */
224 | public function testCreateLinearCreativeWithInteractiveCreativeFileAndMedia()
225 | {
226 | $factory = new Factory();
227 | $document = $factory->create('4.1');
228 |
229 | // insert Ad section
230 | $ad1 = $document
231 | ->createInLineAdSection()
232 | ->setId('ad1')
233 | ->setAdSystem('Ad Server Name')
234 | ->setAdTitle('Ad Title')
235 | ->addImpression('http://ad.server.com/impression');
236 |
237 | $linear = $ad1->createLinearCreative();
238 | $linear->createMediaFile()->setStreamingDelivery();
239 | $linear->createInteractiveCreativeFile()->setType('text/html')->setApiFramework('SIMID')->setUrl('http://example.com/index.html');
240 |
241 | $this->assertVastDocumentSameWithXmlFixture('linearCreativeWithInteractiveCreativeAndMediaFile.xml', $document);
242 | }
243 |
244 | /**
245 | * Test for creating media file with specific delivery
246 | */
247 | public function testCreateAdSectionWithDelivery()
248 | {
249 | $factory = new Factory();
250 | $document = $factory->create('2.0');
251 |
252 | // insert Ad section
253 | $ad1 = $document
254 | ->createInLineAdSection()
255 | ->setId('ad1')
256 | ->setAdSystem('Ad Server Name')
257 | ->setAdTitle('Ad Title')
258 | ->addImpression('http://ad.server.com/impression');
259 | $ad1->createLinearCreative()->createMediaFile()->setDelivery('progressive');
260 |
261 | $this->assertVastDocumentSameWithXmlFixture('adWithDelivery.xml', $document);
262 | }
263 |
264 | /**
265 | * Test for creating media file with invalid delivery
266 | */
267 | public function testCreateAdSectionWithInvalidDelivery()
268 | {
269 | $this->expectExceptionMessage('Wrong delivery specified');
270 | $factory = new Factory();
271 | $document = $factory->create('2.0');
272 |
273 | // insert Ad section
274 | $ad1 = $document
275 | ->createInLineAdSection()
276 | ->setId('ad1')
277 | ->setAdSystem('Ad Server Name')
278 | ->setAdTitle('Ad Title')
279 | ->addImpression('http://ad.server.com/impression');
280 |
281 | // create creative for ad section
282 | $ad1
283 | ->createLinearCreative()
284 | ->setDuration(128)
285 | ->setVideoClicksClickThrough('http://entertainmentserver.com/landing')
286 | ->addVideoClicksClickTracking('http://ad.server.com/videoclicks/clicktracking')
287 | ->addVideoClicksCustomClick('http://ad.server.com/videoclicks/customclick')
288 | ->addTrackingEvent('start', 'http://ad.server.com/trackingevent/start')
289 | ->addTrackingEvent('pause', 'http://ad.server.com/trackingevent/stop')
290 | ->skipAfter(1519203721)
291 | ->createMediaFile()
292 | ->setDelivery('invalid_delivery')
293 | ->setType('video/mp4')
294 | ->setHeight(100)
295 | ->setWidth(100)
296 | ->setUrl('http://server.com/media.mp4');
297 | }
298 |
299 | /**
300 | * Test for ad with extension
301 | */
302 | public function testCreateAdSectionWithAddingExtension()
303 | {
304 | $factory = new Factory();
305 | $document = $factory->create('2.0');
306 |
307 | // insert Ad section
308 | $ad1 = $document
309 | ->createInLineAdSection()
310 | ->setId('ad1')
311 | ->setAdSystem('Ad Server Name')
312 | ->setAdTitle('Ad Title')
313 | ->addImpression('http://ad.server.com/impression');
314 | $ad1->addExtension('extension_type', 'extension_value');
315 |
316 | $this->assertVastDocumentSameWithXmlFixture('inlineAdWithExtension.xml', $document);
317 |
318 | $document = $factory->create('2.0');
319 |
320 | // insert Ad section
321 | $ad1 = $document
322 | ->createWrapperAdSection()
323 | ->setId('ad1')
324 | ->setVASTAdTagURI('//entertainmentserver.com/vast1.xml')
325 | ->setAdSystem('Ad Server Name')
326 | ->addImpression('http://ad.server.com/impression');
327 | $ad1->addExtension('extension_type', 'extension_value');
328 |
329 | $this->assertVastDocumentSameWithXmlFixture('wrapperAdWithExtension.xml', $document);
330 | }
331 |
332 | /**
333 | * Test for Document with set sequence
334 | */
335 | public function testCreateAdSectionWithSettingSequence()
336 | {
337 | $factory = new Factory();
338 | $document = $factory->create('2.0');
339 |
340 | // insert Ad section
341 | $ad1 = $document
342 | ->createInLineAdSection()
343 | ->setId('ad1')
344 | ->setAdSystem('Ad Server Name')
345 | ->setAdTitle('Ad Title')
346 | ->setSequence(0)
347 | ->addImpression('http://ad.server.com/impression');
348 |
349 | $this->assertSame(0, $ad1->getSequence());
350 | }
351 |
352 | /**
353 | * Test for wrapper ad
354 | */
355 | public function testCreateWrapperAdSection()
356 | {
357 | $factory = new Factory();
358 | $document = $factory->create('2.0');
359 | $this->assertInstanceOf('\Sokil\Vast\Document', $document);
360 |
361 | // insert Ad section
362 | $document
363 | ->createWrapperAdSection()
364 | ->setId('ad1')
365 | ->setVASTAdTagURI('//entertainmentserver.com/vast1.xml')
366 | ->setAdSystem('Ad Server Name')
367 | ->setVASTAdTagURI('//entertainmentserver.com/vast2.xml')
368 | ->createLinearCreative()
369 | ->addVideoClicksClickTracking('//ad.server.com/videoclicks/clicktracking')
370 | ->addVideoClicksCustomClick('//ad.server.com/videoclicks/customclick')
371 | ->addTrackingEvent('start', '//ad.server.com/trackingevent/start')
372 | ->addTrackingEvent('pause', '//ad.server.com/trackingevent/stop');
373 |
374 | $this->assertVastDocumentSameWithXmlFixture('wrapper.xml', $document);
375 | }
376 |
377 | /**
378 | * Error trait in document
379 | */
380 | public function testErrorInDocument()
381 | {
382 | $factory = new Factory();
383 | $document = $factory->create('3.0');
384 | $document->addErrors('//ad.server.com/tracking/error/noad');
385 |
386 | $this->assertVastDocumentSameWithXmlFixture('error.xml', $document);
387 |
388 | $this->assertEquals(
389 | array('//ad.server.com/tracking/error/noad'),
390 | $document->getErrors()
391 | );
392 | }
393 |
394 | /**
395 | * Error trait in wrapper ad
396 | */
397 | public function testErrorInWrapperAd()
398 | {
399 | $factory = new Factory();
400 | $document = $factory->create('2.0');
401 | $this->assertInstanceOf('\Sokil\Vast\Document', $document);
402 |
403 | // insert Ad section
404 | $wrapperAd = $document
405 | ->createWrapperAdSection()
406 | ->setId('ad1')
407 | ->setAdSystem('Ad Server Name')
408 | ->setVASTAdTagURI('//entertainmentserver.com/vast1.xml')
409 | ->addError('//ad.server.com/tracking/error');
410 |
411 | $this->assertVastDocumentSameWithXmlFixture('errorInWrapper.xml', $document);
412 |
413 | $this->assertEquals(
414 | array('//ad.server.com/tracking/error'),
415 | $wrapperAd->getErrors()
416 | );
417 | }
418 |
419 | /**
420 | * Error trait in inline ad
421 | */
422 | public function testErrorInInlineAd()
423 | {
424 | $factory = new Factory();
425 | $document = $factory->create('2.0');
426 | $this->assertInstanceOf('\Sokil\Vast\Document', $document);
427 |
428 | // insert Ad section
429 | $ad1 = $document
430 | ->createInLineAdSection()
431 | ->setId('ad1')
432 | ->setAdSystem('Ad Server Name')
433 | ->addError('//ad.server.com/tracking/error');
434 |
435 | $this->assertVastDocumentSameWithXmlFixture('errorInInline.xml', $document);
436 |
437 | $this->assertEquals(
438 | array('//ad.server.com/tracking/error'),
439 | $ad1->getErrors()
440 | );
441 | }
442 |
443 | /**
444 | * Impression trait in wrapper ad
445 | */
446 | public function testImpressionInWrapperAd()
447 | {
448 | $factory = new Factory();
449 | $document = $factory->create('2.0');
450 | $this->assertInstanceOf('\Sokil\Vast\Document', $document);
451 |
452 | // insert Ad section
453 | $ad1 = $document
454 | ->createWrapperAdSection()
455 | ->setId('ad1')
456 | ->setAdSystem('Ad Server Name')
457 | ->setVASTAdTagURI('//entertainmentserver.com/vast1.xml')
458 | ->addImpression('//ad.server.com/tracking/impression1')
459 | ->addImpression('//ad.server.com/tracking/impression2');
460 |
461 | $this->assertVastDocumentSameWithXmlFixture('impressionInWrapper.xml', $document);
462 |
463 | $this->assertEquals(
464 | array(
465 | '//ad.server.com/tracking/impression1',
466 | '//ad.server.com/tracking/impression2',
467 | ),
468 | $ad1->getImpressions()
469 | );
470 | }
471 |
472 | /**
473 | * test Document to output string
474 | */
475 | public function testToString()
476 | {
477 | $factory = new Factory();
478 | $document = $factory->create('2.0');
479 |
480 | $this->assertStringContainsString('', (string)$document);
481 | $this->assertStringContainsString('', (string)$document);
482 | }
483 |
484 | /**
485 | * test Document to output \DomDocument
486 | */
487 | public function testToDomDocument()
488 | {
489 | $factory = new Factory();
490 | $document = $factory->create('2.0');
491 |
492 | $this->assertInstanceOf('\DomDocument', $document->toDomDocument());
493 | }
494 |
495 | /**
496 | * test Document to create another vast version from Document
497 | */
498 | public function testCreate()
499 | {
500 | $factory = new Factory();
501 | $document = $factory->create('2.0');
502 |
503 | $this->assertInstanceOf('\DomDocument', $document->toDomDocument());
504 | }
505 |
506 | /**
507 | * test Document to create vast from string
508 | */
509 | public function testFromString()
510 | {
511 | $factory = new Factory();
512 |
513 | $this->assertInstanceOf(
514 | 'Sokil\Vast\Document',
515 | $factory->fromString('')
516 | );
517 | }
518 |
519 | /**
520 | * test Document to create vast from file
521 | */
522 | public function testFromFile()
523 | {
524 | $factory = new Factory();
525 |
526 | $this->assertInstanceOf('Sokil\Vast\Document', $factory->fromFile(__DIR__ . '/data/vast.xml'));
527 | }
528 |
529 | /**
530 | * VPAID creative test
531 | */
532 | public function testVpaidCreative()
533 | {
534 | $factory = new Factory();
535 | $document = $factory->create('3.0');
536 |
537 | $ad = $document
538 | ->createInLineAdSection()
539 | ->setId('test-vpaid')
540 | ->setAdSystem('Ad Server Name')
541 | ->setAdTitle('VPAIDPreRoll');
542 |
543 | $creative = $ad->createLinearCreative();
544 | $creative
545 | ->setAdParameters(array(
546 | 'param' => 42,
547 | ))
548 | ->setAdParameters(array(
549 | 'list' => array(
550 | array('param1' => 'value1', 'param2' => 'value2')
551 | ),
552 | ));
553 |
554 | $creative->createMediaFile()
555 | ->setApiFramework('VPAID')
556 | ->setType('application/javascript')
557 | ->setUrl('https://example.com/vpaid.js?v434');
558 |
559 | $this->assertVastDocumentSameWithXmlFixture('vpaid.xml', $document);
560 | }
561 | }
562 |
--------------------------------------------------------------------------------
/tests/ElementBuilderTest.php:
--------------------------------------------------------------------------------
1 | create('4.1');
15 | $this->assertInstanceOf('\\Sokil\\Vast\\Stub\\CustomElementBuilder\\Element\\CustomDocument', $document);
16 |
17 | // insert Ad section
18 | $inLineAd = $document
19 | ->createInLineAdSection()
20 | ->setId('ad1')
21 | ->setAdSystem('Ad Server Name')
22 | ->setAdTitle('Ad Title')
23 | ->addImpression('http://ad.server.com/impression', 'imp1');
24 |
25 | $this->assertInstanceOf('\\Sokil\\Vast\\Stub\\CustomElementBuilder\\Element\\CustomInLine', $inLineAd);
26 |
27 | // create creative for ad section
28 | $inLineAdLinearCreative = $inLineAd
29 | ->createLinearCreative()
30 | ->setDuration(128)
31 | ->setUniversalAdId('ad-server.com', '15051996')
32 | ->setVideoClicksClickThrough('http://entertainmentserver.com/landing')
33 | ->addVideoClicksClickTracking('http://ad.server.com/videoclicks/clicktracking')
34 | ->addVideoClicksCustomClick('http://ad.server.com/videoclicks/customclick')
35 | ->addTrackingEvent('start', 'http://ad.server.com/trackingevent/start')
36 | ->addTrackingEvent('pause', 'http://ad.server.com/trackingevent/stop')
37 | ->addProgressTrackingEvent('http://ad.server.com/trackingevent/progress', 10);
38 |
39 | $this->assertInstanceOf('\\Sokil\\Vast\\Stub\\CustomElementBuilder\\Element\\CustomInLineAdLinearCreative', $inLineAdLinearCreative);
40 |
41 | $mediaFile = $inLineAdLinearCreative
42 | ->createMediaFile()
43 | ->setProgressiveDelivery()
44 | ->setType('video/mp4')
45 | ->setHeight(100)
46 | ->setWidth(100)
47 | ->setBitrate(600)
48 | ->setUrl('http://server.com/media.mp4');
49 |
50 | $this->assertInstanceOf('\\Sokil\\Vast\\Stub\\CustomElementBuilder\\Element\\CustomMediaFile', $mediaFile);
51 |
52 | $this->assertVastDocumentSameWithXmlFixture('inlineAdCustomElements.xml', $document);
53 | }
54 | }
--------------------------------------------------------------------------------
/tests/FactoryTest.php:
--------------------------------------------------------------------------------
1 | fromFile(__DIR__ . '/data/vast.xml');
11 |
12 | // check if loaded
13 | $this->assertInstanceOf(
14 | 'Sokil\Vast\Document',
15 | $vastDocument
16 | );
17 |
18 | // get first ad section
19 | $adSections = $vastDocument->getAdSections();
20 | $adSection = $adSections[0];
21 |
22 | // get scalar node
23 | $adSystem = $adSection->getAdSystem();
24 | $this->assertSame('Ad Server Name', $adSystem);
25 |
26 | // get multi-nodes
27 |
28 | $this->assertEquals(
29 | array(
30 | 'http://ad.server.com/impression1',
31 | 'http://ad.server.com/impression2',
32 | 'http://ad.server.com/impression3',
33 | ),
34 | $adSection->getImpressions()
35 | );
36 | }
37 |
38 | public function testFromString()
39 | {
40 | $factory = new Factory();
41 | $vastDocument = $factory->fromString(file_get_contents(__DIR__ . '/data/vast.xml'));
42 |
43 | $this->assertInstanceOf(
44 | 'Sokil\Vast\Document',
45 | $vastDocument
46 | );
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/tests/Stub/CustomElementBuilder/CustomElementBuilder.php:
--------------------------------------------------------------------------------
1 | with inside
23 | *
24 | * @param \DomDocument $xmlDocument
25 | *
26 | * @return CustomDocument
27 | */
28 | public function createDocument(\DomDocument $xmlDocument): Document
29 | {
30 | return new CustomDocument(
31 | $xmlDocument,
32 | $this
33 | );
34 | }
35 |
36 | /**
37 | * with inside
38 | *
39 | * @param \DomElement $adElement
40 | *
41 | * @return CustomInLine
42 | */
43 | public function createInLineAdNode(\DomElement $adElement): InLine
44 | {
45 | return new CustomInLine($adElement, $this);
46 | }
47 |
48 | /**
49 | * with inside
50 | *
51 | * @param \DomElement $adElement
52 | *
53 | * @return CustomWrapper
54 | */
55 | public function createWrapperAdNode(\DomElement $adElement): Wrapper
56 | {
57 | return new CustomWrapper($adElement, $this);
58 | }
59 |
60 | /**
61 | * with inside
62 | *
63 | * @param \DOMElement $creativeDomElement
64 | *
65 | * @return CustomInLineAdLinearCreative
66 | */
67 | public function createInLineAdLinearCreative(\DOMElement $creativeDomElement): InLineAdLinearCreative
68 | {
69 | return new CustomInLineAdLinearCreative($creativeDomElement, $this);
70 | }
71 |
72 | /**
73 | * with inside
74 | *
75 | * @param \DOMElement $creativeDomElement
76 | *
77 | * @return CustomWrapperAdLinearCreative
78 | */
79 | public function createWrapperAdLinearCreative(\DOMElement $creativeDomElement): WrapperAdLinearCreative
80 | {
81 | return new CustomWrapperAdLinearCreative($creativeDomElement, $this);
82 | }
83 |
84 | /**
85 | *
86 | *
87 | * @param \DOMElement $mediaFileDomElement
88 | *
89 | * @return CustomMediaFile
90 | */
91 | public function createInLineAdLinearCreativeMediaFile(\DOMElement $mediaFileDomElement): MediaFile
92 | {
93 | return new CustomMediaFile($mediaFileDomElement);
94 | }
95 |
96 | }
--------------------------------------------------------------------------------
/tests/Stub/CustomElementBuilder/Element/CustomDocument.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/tests/data/error.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/tests/data/errorInInline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/tests/data/errorInWrapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/tests/data/impressionInWrapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/tests/data/inlineAd.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | 15051996
13 |
14 | 00:02:08
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/tests/data/inlineAdCustomElements.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 15051996
11 |
12 | 00:02:08
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/tests/data/inlineAdWithExtension.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/tests/data/linearCreativeWithClosedCaption.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/tests/data/linearCreativeWithClosedCaptionAndMediaFile.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/tests/data/linearCreativeWithInteractiveCreativeAndMediaFile.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/tests/data/linearCreativeWithSkipAfter.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/tests/data/linearCreativeWithStreamingDelivery.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/tests/data/replacedClickThrough.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/tests/data/vast.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | 00:02:08
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/tests/data/vpaid.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/tests/data/wrapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/tests/data/wrapperAdWithExtension.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/tests/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ../src
6 |
7 |
8 |
9 |
10 | ./
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------