Skip to content

Commit

Permalink
Merge pull request #148 from bennetgallein/feat/create-object-support
Browse files Browse the repository at this point in the history
Support passing `ResourceRecord` objects when creating new records
  • Loading branch information
trizz authored Nov 20, 2023
2 parents 357807c + 909cbe5 commit 8b25fc0
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 11 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Basic example how to create a new DNS zone and insert a few DNS records.
```php
use Exonet\Powerdns\Powerdns;
use Exonet\Powerdns\RecordType;
use Exonet\Powerdns\Resources\ResourceRecord;
use Exonet\Powerdns\Resources\Record;

// Initialize the Powerdns client.
$powerdns = new Powerdns('127.0.0.1', 'powerdns_secret_string');
Expand All @@ -33,6 +35,12 @@ $zone->create([
['type' => RecordType::A, 'content' => '127.0.0.1', 'ttl' => 60, 'name' => '@'],
['type' => RecordType::A, 'content' => '127.0.0.1', 'ttl' => 60, 'name' => 'www'],
]);

// OR use the Object-based way
$zone->create([
(new ResourceRecord())->setType(RecordType::A)->setRecord('127.0.0.1')->setName('@')->setTtl(60),
(new ResourceRecord())->setType(RecordType::A)->setRecord((new Record())->setContent('127.0.0.1'))->setName('@')->setTtl(60),
]);
```

See the [examples](examples) directory for more.
Expand Down
13 changes: 11 additions & 2 deletions src/Resources/ResourceRecord.php
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,15 @@ public function getShortName(): string
*/
public function setName(string $name): self
{
if ($this->getZone() !== null) {
$name = str_replace('@', $this->getZone()->getCanonicalName(), $name);

// If the name of the record doesn't end in the zone name, append the zone name to it.
if (substr($name, -strlen($this->getZone()->getCanonicalName())) !== $this->getZone()->getCanonicalName()) {
$name = sprintf('%s.%s', $name, $this->getZone()->getCanonicalName());
}
}

$this->name = $name;

return $this;
Expand Down Expand Up @@ -398,9 +407,9 @@ public function setType(string $type): self
/**
* Get the zone object for this ResourceRecord.
*
* @return Zone The zone for this ResourceRecord.
* @return Zone|null The zone for this ResourceRecord.
*/
public function getZone(): Zone
public function getZone(): ?Zone
{
return $this->zone;
}
Expand Down
27 changes: 18 additions & 9 deletions src/Zone.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace Exonet\Powerdns;

use Exonet\Powerdns\Exceptions\InvalidNsec3Param;
use Exonet\Powerdns\Resources\Record;
use Exonet\Powerdns\Resources\ResourceRecord;
use Exonet\Powerdns\Resources\ResourceSet;
use Exonet\Powerdns\Transformers\DnssecTransformer;
Expand All @@ -21,12 +20,12 @@ class Zone extends AbstractZone
* resource records will be created in a single call to the PowerDNS server. If $name is a string, a single resource
* record is created.
*
* @param mixed[]|string $name The resource record name.
* @param string $type The type of the resource record.
* @param mixed[]|string $content The content of the resource record. When passing a multidimensional array,
* multiple records are created for this resource record.
* @param int $ttl The TTL.
* @param array|mixed[] $comments The comment to assign to the record.
* @param mixed[]|ResourceRecord|ResourceRecord[]|string $name The resource record name.
* @param string $type The type of the resource record.
* @param mixed[]|string $content The content of the resource record. When passing a multidimensional array,
* multiple records are created for this resource record.
* @param int $ttl The TTL.
* @param array|mixed[] $comments The comment to assign to the record.
*
* @throws Exceptions\InvalidRecordType If the given type is invalid.
*
Expand All @@ -37,10 +36,20 @@ public function create($name, string $type = '', $content = '', int $ttl = 3600,
if (is_array($name)) {
$resourceRecords = [];
foreach ($name as $item) {
$resourceRecords[] = $this->make($item['name'], $item['type'], $item['content'], $item['ttl'] ?? $ttl, $item['comments'] ?? []);
if ($item instanceof ResourceRecord) {
$item->setZone($this)->setName($item->getName());
$resourceRecords[] = $item;
} else {
$resourceRecords[] = $this->make($item['name'], $item['type'], $item['content'], $item['ttl'] ?? $ttl, $item['comments'] ?? []);
}
}
} else {
$resourceRecords = [$this->make($name, $type, $content, $ttl, $comments)];
if ($name instanceof ResourceRecord) {
$name->setZone($this)->setName($name->getName());
$resourceRecords = [$name];
} else {
$resourceRecords = [$this->make($name, $type, $content, $ttl, $comments)];
}
}

return $this->patch($resourceRecords);
Expand Down
101 changes: 101 additions & 0 deletions tests/ZoneTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
namespace Exonet\Powerdns\tests;

use Exonet\Powerdns\Connector;
use Exonet\Powerdns\RecordType;
use Exonet\Powerdns\Resources\Comment;
use Exonet\Powerdns\Resources\Record;
use Exonet\Powerdns\Resources\ResourceRecord;
use Exonet\Powerdns\Resources\Zone as ZoneResource;
use Exonet\Powerdns\Transformers\RRSetTransformer;
use Exonet\Powerdns\Zone;
Expand Down Expand Up @@ -61,6 +65,34 @@ public function testCreateSingleResourceRecord(): void
$zone->create('test', 'A', '127.0.0.1', 10);
}

public function testCreateSingleResourceRecordFromClass(): void
{
$connector = Mockery::mock(Connector::class);
$connector->shouldReceive('patch')->withArgs(['zones/test.nl.', Mockery::on(function (RRSetTransformer $transformer) {
$data = $transformer->transform();

$this->assertSame('test.test.nl.', $data->rrsets[0]->name);
$this->assertSame('A', $data->rrsets[0]->type);
$this->assertSame(10, $data->rrsets[0]->ttl);
$this->assertSame('127.0.0.1', $data->rrsets[0]->records[0]->content);

return true;
})]);

$zone = new Zone($connector, 'test.nl');
$rr = (new ResourceRecord())
->setName('test.test.nl.')
->setType(RecordType::A)
->setRecord('127.0.0.1')
->setTtl(10)
->setComments([
(new Comment())->setContent('Hello')->setAccount('root')->setModifiedAt(1),
(new Comment())->setContent('Power')->setAccount('admin')->setModifiedAt(2),
(new Comment())->setContent('DNS')->setAccount('superuser')->setModifiedAt(3),
]);
$zone->create($rr);
}

public function testCreateMultipleResourceRecords(): void
{
$connector = Mockery::mock(Connector::class);
Expand Down Expand Up @@ -106,6 +138,75 @@ public function testCreateMultipleResourceRecords(): void
]);
}

public function testCreateMultipleResourceRecordsFromClass(): void
{
$connector = Mockery::mock(Connector::class);
$connector->shouldReceive('patch')->withArgs(['zones/test.nl.', Mockery::on(function (RRSetTransformer $transformer) {
$data = $transformer->transform();

$this->assertSame('test.test.nl.', $data->rrsets[0]->name);
$this->assertSame('A', $data->rrsets[0]->type);
$this->assertSame(10, $data->rrsets[0]->ttl);
$this->assertSame('127.0.0.1', $data->rrsets[0]->records[0]->content);

$this->assertSame('test.nl.', $data->rrsets[1]->name);
$this->assertSame('A', $data->rrsets[1]->type);
$this->assertSame(20, $data->rrsets[1]->ttl);
$this->assertSame('127.0.0.1', $data->rrsets[1]->records[0]->content);

$this->assertSame('test.nl.', $data->rrsets[2]->name);
$this->assertSame('MX', $data->rrsets[2]->type);
$this->assertSame(30, $data->rrsets[2]->ttl);
$this->assertSame('10 mail01.test.nl.', $data->rrsets[2]->records[0]->content);
$this->assertSame('20 mail02.test.nl.', $data->rrsets[2]->records[1]->content);

$this->assertSame('test02.test.nl.', $data->rrsets[3]->name);
$this->assertSame('A', $data->rrsets[3]->type);
$this->assertSame(40, $data->rrsets[3]->ttl);
$this->assertSame('127.0.0.1', $data->rrsets[3]->records[0]->content);

$this->assertSame('test03.test.nl.', $data->rrsets[4]->name);
$this->assertSame('TXT', $data->rrsets[4]->type);
$this->assertSame(40, $data->rrsets[4]->ttl);
$this->assertSame('"v=DMARC1; p=none; rua=mailto:info@test.nl; ruf=mailto:info@test.nl"', $data->rrsets[4]->records[0]->content);

return true;
})]);

$zone = new Zone($connector, 'test.nl');
$zone->create([
(new ResourceRecord())
->setName('test')
->setType(RecordType::A)
->setRecord((new Record())
->setContent('127.0.0.1'))
->setTtl(10),
(new ResourceRecord())
->setName('@')
->setType(RecordType::A)
->setRecord((new Record())->setContent('127.0.0.1'))
->setTtl(20),
(new ResourceRecord())
->setName('@')
->setType(RecordType::MX)
->setRecords([
(new Record())->setContent('10 mail01.test.nl.'),
(new Record())->setContent('20 mail02.test.nl.'),
])
->setTtl(30),
(new ResourceRecord())
->setName('test02')
->setType(RecordType::A)
->setRecord((new Record())->setContent('127.0.0.1'))
->setTtl(40),

(new ResourceRecord())
->setName('test03')
->setType(RecordType::TXT)->setRecord((new Record())->setContent('"v=DMARC1; p=none; rua=mailto:info@test.nl; ruf=mailto:info@test.nl"'))
->setTtl(40),
]);
}

public function testCreateNoResourceRecords(): void
{
$connector = Mockery::mock(Connector::class);
Expand Down

0 comments on commit 8b25fc0

Please sign in to comment.