2

I am using a library from Github that I am adding to my project via Composer. In my code, I want to extend the library classes. I would normally be able to do this with a simple extend and new e.g.

class myNewClasses extends classesFromTheLibrary
{
// add my custom methods here
}

// instantiate with new
$allClasses = new myNewClasses; // $allClasses can access methods in myNewClasses and classesFromTheLibrary

But, this library is instantiated as follows:

$document = \Sokil\Vast\Document::create('2.0');

So the new technique can't be used. Also, some of the classes I would like to extend are in different namespaces, such as \Sokil\Vast\Ad\Inline.

How do I extend classes when the instantiated this way and with different namespaces?

For reference, the library I'm trying to use is here ... and I've tried the decorator technique discussed here, but that doesn't seem to work either.

** EDIT **

Perhaps I am barking up the wrong tree here with extends: The ::create('2.0') may be a distraction.

What I am trying to do is add a method to a class in a different namespace to the parent.

The first instantiation happens at the top level: \Sokil\Vast\Document, but the class I want to extend is \Sokil\Vast\Ad\Inline ... but if I extend that class, I can't instantiate it, because it is instantiated within \Sokil\Vast\Document that I don't have access to. Hope that makes sense. Any ideas?

Community
  • 1
  • 1
Steve Dunlop
  • 1,110
  • 2
  • 9
  • 10
  • That looks like it is instantiated via a [static method](http://php.net/manual/en/language.oop5.paamayim-nekudotayim.php). I'm not sure but maybe [this](http://stackoverflow.com/questions/1280492/extending-php-static-classes) is relevant. – Alex W Oct 09 '15 at 18:22
  • 2
    Does `myNewClasses::create("2.0")` not work? The author of that class did not intend it to be easily extended (if he had then he would have used the constructor, not a static method). Complain to the author. – Sverri M. Olsen Oct 09 '15 at 18:26
  • @SverriM.Olsen, No - because [`create()`](https://github.com/sokil/php-vast/blob/master/src/Sokil/Vast/Document.php#L29) will always return an instance of the superclass without additional changes from the subclass. – HPierce Oct 09 '15 at 19:36
  • @SverriM.Olsen and @HPierce, it seems you are both right: `myNewClasses::create("2.0")` does work (when using `extends \Sokil\Vast\Document`), but the additional classes in myNewClasses don't extend to the different namespaces (such as `\Sokil\Vast\Ad\Inline`). – Steve Dunlop Oct 09 '15 at 20:32

2 Answers2

1

Perhaps this would do:

class myDocClass extends \Sokil\Vast\Document {
    private $parentObj;
    public function __construct() {
        $this->parentObj = parent::create('2.0');
    }
}

$myDoc = new myDocClass();

You can't assign to $this, so I've created a property linking to the parent obj, which is instantiated in the create() static method of the parent.

Niloct
  • 9,491
  • 3
  • 44
  • 57
  • This seems to instantiate the class but then errors further down the code where it uses $this saying that it is null. – Steve Dunlop Oct 09 '15 at 20:58
  • What method did you try to call ? All methods from the parent class aren't in `$this`, but they're in `$this->parentObj` (`$this->parentObj->method()` for instance). – Niloct Oct 09 '15 at 21:18
1

Since version 0.6 added ability to override element classes, so any custom element or element's attribute may be added.

First let's create class for MediaFile and add some custom attribute:

<?php

namespace Acme\Vast\ElementBuilder\Element;

use Sokil\Vast\Creative\InLine\Linear\MediaFile;

class AcmeMediaFile extends MediaFile
{
    public function setMinDiration($seconds)
    {
        $seconds = (int)$seconds;
        if ($seconds <= 0) {
            thow new \InvalidArgumentException('Invalid min duration specified, must be positive int')
        }

        $this->domElement->setAttribute('minDuration', $seconds);

        return $this;
    }
}

Now we need to override default element builder and create own MediaFile factory method:

<?php

namespace Acme\Vast\ElementBuilder;

use Sokil\Vast\ElementBuilder;
use Acme\Vast\ElementBuilder\Element\AcmeMediaFile;

class AcmeElementBuilder extends ElementBuilder
{
    /**
     * <Ad><InLine><Creatives><Creative><Linear><MediaFile>
     *
     * @param \DOMElement $mediaFileDomElement
     *
     * @return AcmeMediaFile
     */
    public function createInLineAdLinearCreativeMediaFile(\DOMElement $mediaFileDomElement)
    {
        return new AcmeMediaFile($mediaFileDomElement);
    }
}

Now we need to confugure VAST factory to use overridden element builder:

<?php

use Acme\Vast\ElementBuilder\AcmeElementBuilder;
use Sokil\Vast\Factory;

$elementBuilder = new AcmeElementBuilder();
$factory = new Factory($elementBuilder);

$document = $factory->create('4.1');

$ad = $document->createInLineAdSection();
$creative = $ad->createLinearCreative();
$mediaFile = $creative->createMediaFile();

$mediaFile->setMinDiration(10);

See https://github.com/sokil/php-vast#custom-specification-support for more details.