class CerFieldHandler in Corresponding Entity References 7.3
@class Handles low-level operations for a single field on a single entity. Exposes methods to add, delete and check for references. This will also iterate over the references, returning each one as an EntityDrupalWrapper object.
Hierarchy
- class \CerFieldHandler implements \Countable, \SeekableIterator
Expanded class hierarchy of CerFieldHandler
1 string reference to 'CerFieldHandler'
- CerField::getPluginInfo in includes/
CerField.inc - Returns information about a particular field plugin by its identifier, or all available plugins (i.e., defined by hook_cer_fields()) if no identifier is given. The aggregated result of hook_cer_fields() is statically cached.
File
- includes/
CerFieldHandler.inc, line 14 - Contains CerFieldHandler.
View source
class CerFieldHandler implements Countable, SeekableIterator {
/**
* @var CerField
*/
protected $field;
/**
* @var EntityDrupalWrapper
*/
protected $entity;
/**
* @var EntityMetadataWrapper
*/
protected $value;
/**
* @var integer
*/
protected $delta = 0;
/**
* @var boolean
*/
protected $isMultiValue;
public function __construct(CerField $field, EntityDrupalWrapper $entity) {
$this->field = $field;
$this->entity = $entity;
$this->value = $entity->{$field->name};
$this->isMultiValue = $this->value instanceof EntityListWrapper;
$this
->rewind();
}
/**
* Adds a reference to $entity, validating it first.
*
* @param EntityDrupalWrapper $entity
* The wrapped entity to reference.
*/
public function add(EntityDrupalWrapper $entity) {
if ($this
->validate($entity)) {
$this
->write();
}
}
/**
* Deletes all references to $entity.
*
* @param EntityDrupalWrapper $entity
* The wrapped entity to dereference.
*/
public function delete(EntityDrupalWrapper $entity) {
$entityID = $entity
->getIdentifier();
if ($this->isMultiValue) {
foreach ($this->value as $delta => $ref) {
if ($entityID == $ref
->getIdentifier()) {
$this->value[$delta]
->set(NULL);
}
}
}
elseif ($entityID == $this->value
->getIdentifier()) {
$this->value
->set(NULL);
}
$this
->write();
}
/**
* Validates a potential reference. After doing a cardinality check, the
* reference is validated through the Field Attach API, allowing the module
* which owns the field to do its normal validation logic. If validation
* fails, the error(s) are logged.
*
* @param EntityDrupalWrapper $entity
* The wrapped entity to validate.
*
* @return boolean
*/
protected function validate(EntityDrupalWrapper $entity) {
// Before we do anything else, check that the field has enough space to add the
// reference. If there isn't, bail out so we don't blindly overwrite existing
// field data.
if ($this
->checkCardinality()) {
// Keep the previous value so we can restore it if validation fails.
$prev_value = $this->value
->value();
if ($this->isMultiValue) {
$value = $this->value
->value();
$value[] = $entity
->value();
$this->value
->set($value);
}
else {
$this->value
->set($entity
->value());
}
// Leverage the Field Attach API to validate the reference. If errors occur,
// field_attach_validate() throws FieldValidationException, containing an array
// of every validation error.
try {
// Only validate this field.
field_attach_validate($this->entity
->type(), $this->entity
->value(), array(
'field_name' => $this->field->name,
));
return TRUE;
} catch (FieldValidationException $e) {
foreach ($e->errors as $field) {
foreach ($field as $language) {
foreach ($language as $errors) {
foreach ($errors as $error) {
$this
->logError($error['message'], $entity);
}
}
}
}
$this->value
->set($prev_value);
}
}
else {
$this
->logError('Cannot add reference to !that_link from !field_label on !this_link because there are no more slots available.', $entity);
}
return FALSE;
}
/**
* Checks that there are enough slots in the field to add a reference.
*
* @return boolean
*/
protected function checkCardinality() {
return $this->field->cardinality == FIELD_CARDINALITY_UNLIMITED ? TRUE : $this->field->cardinality > $this
->count();
}
/**
* Saves changes to the entity and resets the iterator.
*/
protected function write() {
$entity_type = $this->entity
->type();
$entityID = $this->entity
->getIdentifier();
$entity = $this->entity
->value();
$entity->cer_processed = TRUE;
entity_save($entity_type, $entity);
// Reload the entity we just saved and cleared from the static cache.
$entities = entity_load($entity_type, (array) $entityID);
$this->entity
->set($entities[$entityID]);
$this
->__construct($this->field, $this->entity);
}
/**
* Logs an error, optionally against a specific entity. If the cer_debug
* variable is set, the error will also be set as a message.
*
* @param string $message
* The untranslated message to log.
*
* @param EntityDrupalWrapper $entity
* The entity that has caused the error, if any.
*/
protected function logError($message, EntityDrupalWrapper $entity = NULL) {
$variables = array(
'!field_name' => $this->field->name,
'!field_type' => $this->field->fieldTypeLabel,
'!field_label' => $this->field->label,
);
$variables['!this_type'] = $this->entity
->type();
$variables['!this_label'] = $this->entity
->label();
// If the entity has a URI, provide a link to it. Otherwise, its "link"
// will just be an unlinked label. Entity API doesn't reliably expose a url
// property on entities, and there doesn't appear to be a way to check for
// it without risking an EntityMetadataWrapperException. So I need to use
// this clunky BS instead...ugh.
$this_uri = entity_uri($this->entity
->type(), $this->entity
->value());
if (isset($this_uri)) {
$variables['!this_url'] = url($this_uri['path'], $this_uri['options']);
$variables['!this_link'] = l($this->entity
->label(), $this_uri['path'], $this_uri['options']);
}
else {
$variables['!this_link'] = $this->entity
->label();
}
if ($entity) {
$variables['!that_type'] = $entity
->type();
$variables['!that_label'] = $entity
->label();
// If the entity has a URI, link to it.
$that_uri = entity_uri($entity
->type(), $entity
->value());
if (isset($that_uri)) {
$variables['!that_url'] = url($that_uri['path'], $that_uri['options']);
$variables['!that_link'] = l($entity
->label(), $that_uri['path'], $that_uri['options']);
}
else {
$variables['!that_link'] = $entity
->label();
}
}
watchdog('cer', $message, $variables, WATCHDOG_ERROR);
if (variable_get('cer_debug', FALSE)) {
drupal_set_message(t($message, $variables), 'error');
}
}
public function getIDs() {
$IDs = array();
if ($this->isMultiValue) {
foreach ($this->value as $ref) {
$IDs[] = $ref
->raw();
}
}
else {
$IDs[] = $this->value
->raw();
}
return array_unique(array_filter($IDs));
}
/**
* Implements Countable::count().
*/
public function count() {
if ($this->isMultiValue) {
return sizeof($this->value);
}
else {
return $this->value
->value() ? 1 : 0;
}
}
/**
* Implements SeekableIterator::seek().
*/
public function seek($position) {
$length = $this
->count();
if ($position < 0) {
$position += $length;
}
if ($position >= 0 && $position < $length) {
$this->delta = $position;
}
else {
throw new OutOfBoundsException(t('Cannot seek to invalid position.'));
}
}
/**
* Implements Iterator::current().
*/
public function current() {
return $this->isMultiValue ? $this->value[$this->delta] : $this->value;
}
/**
* Implements Iterator::key().
*/
public function key() {
return $this
->current()
->getIdentifier();
}
/**
* Implements Iterator::next().
*/
public function next() {
$this->delta++;
}
/**
* Implements Iterator::rewind().
*/
public function rewind() {
$this->delta = 0;
}
/**
* Implements Iterator::valid().
*/
public function valid() {
return $this->delta < $this
->count();
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
CerFieldHandler:: |
protected | property | ||
CerFieldHandler:: |
protected | property | ||
CerFieldHandler:: |
protected | property | ||
CerFieldHandler:: |
protected | property | ||
CerFieldHandler:: |
protected | property | ||
CerFieldHandler:: |
public | function | Adds a reference to $entity, validating it first. | |
CerFieldHandler:: |
protected | function | Checks that there are enough slots in the field to add a reference. | |
CerFieldHandler:: |
public | function | Implements Countable::count(). | |
CerFieldHandler:: |
public | function | Implements Iterator::current(). | |
CerFieldHandler:: |
public | function | Deletes all references to $entity. | |
CerFieldHandler:: |
public | function | ||
CerFieldHandler:: |
public | function | Implements Iterator::key(). | |
CerFieldHandler:: |
protected | function | Logs an error, optionally against a specific entity. If the cer_debug variable is set, the error will also be set as a message. | |
CerFieldHandler:: |
public | function | Implements Iterator::next(). | |
CerFieldHandler:: |
public | function | Implements Iterator::rewind(). | |
CerFieldHandler:: |
public | function | Implements SeekableIterator::seek(). | |
CerFieldHandler:: |
public | function | Implements Iterator::valid(). | |
CerFieldHandler:: |
protected | function | Validates a potential reference. After doing a cardinality check, the reference is validated through the Field Attach API, allowing the module which owns the field to do its normal validation logic. If validation fails, the error(s) are logged. | |
CerFieldHandler:: |
protected | function | Saves changes to the entity and resets the iterator. | |
CerFieldHandler:: |
public | function |