Accessing Fields Get access to field instances

Introduction

Form fields are represented by individual classes which are all based on an abstract class that offers standard getter and setter methods for various field flags.

The Fields Instance

All field instances are encapsulated in a single instance of a SetaPDF_FormFiller_Fields instance which acts simliar to a kind of collection. 

The fields instance could be received by the getFields() method of the FormFiller instance: 

PHP
$fields = $formFiller->getFields();

The instance is internally cached, so several getFields() calls will return references to the same object instance. 

Get a Field Instance

The SetaPDF_FormFiller_Fields class offers various ways to get access to the field instances. It implements common interfaces (ArrayAccess and Iterator), so that it's up to your prefered coding style how you access a field.

To get a field by its name follwing solutions are possible: 

PHP
$fields = $formFiller->getFields();

$field = $fields->get('Surename');
// or
$field = $fields['Surename'];
// or
$allFields = $fields->getAll();
$field = $allFields['Surename'];

Field instances are only created when they were requested. So the getAll() method should be avoided if you only need to access a single or a subset of fields. 

The fields instance also implements Countable and the Iterator interface. So intuitive handling of the fields collection is possible as follows: 

PHP
// get the field count
$fieldCount = count($fields);
// or
$fieldCount = $fields->count();

// let's iterate over all fields
foreach ($fields AS $name => $field) {
    var_dump($field->getValue());
}

Get Field Names

To get all available field names the fields class offers the self-speaking method getNames()

PHP
$fields = $formFiller->getFields();
$fieldNames = $fields->getNames();
foreach ($fieldNames AS $fieldName) {
    echo $fieldName . "\n";
}

Handling of Same Named Fields

In an AcroForm it is possible to assign a single field name to several fields. If such a field is filled the value will be populated to all other same named form fields as well.

The SetaPDF-FormFiller component supports this, too. If same named fields are found their names will get suffixed with a "#" and an incrementing number. These fields will be part of the whole fields collection and may be returned by getAll() or getNames().

If you need to skip additional field instances in e.g. an interation you can use the getQualifiedName() and getOriginalQualifiedName() methods to check for this case: 

PHP
foreach ($fields AS $field) {
    if ($field->getQualifiedName() !== $field->getOriginalQualifiedName())
        continue;

    $field->setValue(...);
}

However the passed value will be forwarded to all other same named fields automatically.

An online-demo is available here.

If you need to access the related fields to prepare them with e.g. an external font program you can use the getRelatedFields() method of the fields class to get access to all related field instances:

PHP
$font = new \SetaPDF_Core_Font_TrueType_Subset($document, 'path/to/a/TrueType/Font.ttf');

foreach ($fields->getRelatedFields('FieldName', false) as $field) {
    $field->setAppearanceFont($font);
}

$fields['FieldName']->setValue($value);

Trigger Field Calculations

When prepopulating field values with the SetaPDF-FormFiller component to fields which are part of a computation the calculation is not triggered, because this is done by JavaScript in a reader application.

To trigger the computation a simple document level JavaScript has to be added to the original document:

this.calculateNow(); // in Doc context

If the PDF document is not right/reader enabled it is also possible to add this JavaScript via the Core component

PHP
<?php
require_once('library/SetaPDF/Autoload.php');

// setup a document instance
$writer = new \SetaPDF_Core_Writer_Http('calculated.pdf', true);
$document = \SetaPDF_Core_Document::loadByFilename('files/pdfs/forms/Calculated-And-Formatted.pdf', $writer);

// get a form filler instance
$formFiller = new \SetaPDF_FormFiller($document);
// force re-formatting
$formFiller->setNeedAppearances(true);

// get access to the fields
$fields = $formFiller->getFields();

// fill the fields A and B which should be summed up in C
$fields['A']->setValue(rand(1, 100)); // add some randomness
$fields['B']->setValue('21');

// now add a javascript, that executes the calculation
$javaScripts = $document->getCatalog()->getNames()->getTree(\SetaPDF_Core_Document_Catalog_Names::JAVA_SCRIPT, true);
$name = 'SetasignCalculateNow';
// Check if this script is already included (choose a unique name)
if (!$javaScripts->get($name)) {
    // create a java script action
    $javaScript = new \SetaPDF_Core_Document_Action_JavaScript('this.calculateNow();');
    // add it
    $javaScripts->add($name, new \SetaPDF_Core_Type_IndirectReference($javaScript->getIndirectObject($document)));
}

// save the document
$document->save()->finish();