class AmpMetadataForm in Accelerated Mobile Pages (AMP) 8
Class AmpMetadataForm.
@package Drupal\amp\Form
Hierarchy
- class \Drupal\Core\Form\FormBase implements ContainerInjectionInterface, FormInterface uses DependencySerializationTrait, LoggerChannelTrait, MessengerTrait, LinkGeneratorTrait, RedirectDestinationTrait, UrlGeneratorTrait, StringTranslationTrait
- class \Drupal\Core\Entity\EntityForm implements EntityFormInterface
- class \Drupal\amp\Form\AmpMetadataForm implements \Symfony\Component\DependencyInjection\ContainerAwareInterface
- class \Drupal\Core\Entity\EntityForm implements EntityFormInterface
Expanded class hierarchy of AmpMetadataForm
File
- src/
Form/ AmpMetadataForm.php, line 25
Namespace
Drupal\amp\FormView source
class AmpMetadataForm extends EntityForm implements ContainerAwareInterface {
/**
* The container.
*
* @var \Symfony\Component\DependencyInjection\ContainerInterface
*/
protected $container;
/**
* The AMP metadata info service.
*
* @var \Drupal\amp\AmpMetadataInfo
*/
protected $ampMetadataInfo;
/**
* The file usage service.
*
* @var \Drupal\file\FileUsage\DatabaseFileUsageBackend
*/
protected $fileUsage;
/**
* The cache tags invalidator.
*
* @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface
*/
protected $tagInvalidate;
/**
* The module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* Constructs a AmpMetadataForm object.
*
* @param \Drupal\amp\AmpMetadataInfo $amp_metadata_info
* The AMP metadata info service.
* @param \Drupal\file\FileUsage\DatabaseFileUsageBackend
* The file usage service.
* @param \Drupal\Core\Cache\CacheTagsInvalidatorInterface $tag_invalidate
* The cache tags invalidator.
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
*/
public function __construct(AmpMetadataInfo $amp_metadata_info, DatabaseFileUsageBackend $file_usage, CacheTagsInvalidatorInterface $tag_invalidate, ModuleHandlerInterface $module_handler) {
$this->ampMetadataInfo = $amp_metadata_info;
$this->fileUsage = $file_usage;
$this->tagInvalidate = $tag_invalidate;
$this->moduleHandler = $module_handler;
}
/**
* Sets the Container.
*
* @param ContainerInterface|null $container A ContainerInterface instance or null
*/
public function setContainer(ContainerInterface $container = null) {
$this->container = $container;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static($container
->get('amp.metadata'), $container
->get('file.usage'), $container
->get('cache_tags.invalidator'), $container
->get('module_handler'));
}
/**
* {@inheritdoc}
*/
public function form(array $form, FormStateInterface $form_state) {
$form = parent::form($form, $form_state);
/** @var AmpMetadata $amp_metadata */
$amp_metadata = $this->entity;
// Check if global metadata settings already exist.
$amp_metadata_global_exists = $this->ampMetadataInfo
->ampMetadataHasGlobal();
// Get AMP-enabled node types without existing settings.
$node_type_options = $this->ampMetadataInfo
->getAmpNodeTypesWithoutMetadataSettings();
if (!$this->moduleHandler
->moduleExists('token')) {
// Provide message in case somebody has upgraded AMP module but has not
// installed Token.
drupal_set_message($this
->t('The AMP module now requires the <a href="@module">Token</a> module as a dependency. Please download and install Token in order for AMP metadata to appear properly.', [
'@module' => 'https://www.drupal.org/project/token',
]), 'warning');
}
$introduction_title = $amp_metadata_global_exists && !$amp_metadata
->isGlobal() ? $this
->t('Content type override for metadata settings') : $this
->t('Global metadata settings');
$top_stories_guidelines_url = Url::fromUri('https://developers.google.com/search/docs/data-types/articles#article_types');
$form['introduction'] = [
'#type' => 'item',
'#title' => $introduction_title,
'#description' => t('These metadata settings provide information used in the Top Stories carousel in Google Search. Find complete details in the <a href=":top_stories_guidelines">Top Stories guidelines</a>.', [
':top_stories_guidelines' => $top_stories_guidelines_url
->toString(),
]),
];
// Show a node type selector if this is new metadata, and global metadata
// settings already exist.
if ($amp_metadata
->isNew() && $amp_metadata_global_exists) {
$form['node_type'] = array(
'#type' => 'select',
'#title' => t('Content type'),
'#description' => t('Select a content type for which you would like to override the global AMP metadata setting. Settings are overridden on a field by field basis.'),
'#options' => $node_type_options,
'#required' => TRUE,
'#default_value' => NULL,
);
}
// Add a collapsible section for organization information. Open by default
// for global settings.
$show_organization_fields = $amp_metadata_global_exists && !$amp_metadata
->isGlobal() ? FALSE : TRUE;
$form['organization_group'] = [
'#type' => 'details',
'#title' => 'Organization information',
'#open' => $show_organization_fields,
];
$form['organization_group']['description'] = [
'#type' => 'item',
'#description' => t('Provide information about your organization for use in search metadata.'),
];
// Add the token browser for ease in selecting token values.
$form['organization_group']['token_link'] = [
'#theme' => 'token_tree_link',
'#token_types' => 'all',
'#global_types' => TRUE,
'#click_insert' => TRUE,
'#show_restricted' => FALSE,
'#recursion_limit' => 3,
'#text' => t('Browse available tokens'),
];
// Add an option to set the organization name that appears in the carousel.
$org_name = $amp_metadata
->getOrganizationName();
$form['organization_group']['amp_organization_name'] = [
'#type' => 'textfield',
'#title' => t('Organization name'),
'#description' => t('The name of the organization that will appear in the Top Stories carousel. Tokens are allowed.'),
'#default_value' => $org_name ? $org_name : '',
'#attributes' => [
'placeholder' => '[site:name]',
],
];
// Add an option to upload an organizational logo for the carousel.
$top_stories_logo_guidelines_url = Url::fromUri('https://developers.google.com/search/docs/data-types/articles#amp-logo-guidelines');
$logo_config_fid = $amp_metadata
->getOrganizationLogoFid();
$default_logo_fid = $logo_config_fid ? [
$logo_config_fid,
] : NULL;
$form['organization_group']['amp_organization_logo_fid_new'] = [
'#type' => 'managed_file',
'#title' => t('Organization logo'),
'#description' => t('Upload a logo for your organization that will appear in the Top Stories carousel. <span class="warning">This logo must have a height of 60px and a width less than 600px. SVG logos are not allowed: please provide a JPG, JPEG, GIF or PNG. See the AMP <a href=":logo_guidelines">logo guidelines</a>.</span>', [
':logo_guidelines' => $top_stories_logo_guidelines_url
->toString(),
]),
'#default_value' => $default_logo_fid,
'#upload_location' => 'public://amp',
'#upload_validators' => [
'file_validate_is_image' => [],
'file_validate_extensions' => [
'png gif jpg jpeg',
],
'file_validate_image_resolution' => [
'600x60',
],
],
];
// Store the initial logo file ID. This will help us determine if the logo
// file is removed, in which case we should delete the file.
$form['organization_group']['amp_organization_logo_fid_previous'] = [
'#type' => 'hidden',
'#value' => $default_logo_fid,
];
// Add an option to select an image style for the organization logo.
$org_logo_style = $amp_metadata
->getOrganizationLogoImageStyleId();
$form['organization_group']['amp_organization_logo_image_style_id'] = [
'#type' => 'select',
'#title' => t('Organization logo image style'),
'#options' => image_style_options(TRUE),
'#description' => t('The image style to use for the organization logo.'),
'#default_value' => $org_logo_style ? $org_logo_style : '',
];
// Add a section for content information.
$form['content_group'] = [
'#type' => 'fieldset',
'#title' => 'Content information',
];
$form['content_group']['description'] = [
'#type' => 'item',
'#description' => t('Provide information about your content for use in the Top Stories carousel in Google Search.'),
];
// Add an option to select the schema type for AMP pages.
$schema_type_options = [
'Article' => 'Article',
'NewsArticle' => 'NewsArticle',
'BlogPosting' => 'BlogPosting',
];
$schema_type = $amp_metadata
->getContentSchemaType();
$form['content_group']['amp_content_schema_type'] = [
'#type' => 'select',
'#title' => t('AMP schema type'),
'#options' => $schema_type_options,
'#description' => t('The type of schema to use on AMP pages'),
'#default_value' => $schema_type ? $schema_type : 'NewsArticle',
];
// Add an option to set the headline on AMP pages.
$content_headline = $amp_metadata
->getContentHeadlineToken();
$form['content_group']['amp_content_headline'] = [
'#type' => 'textfield',
'#title' => t('Article headline'),
'#description' => t('A short headline for an AMP article, using fewer than 110 characters and no HTML markup. Use tokens to provide the correct headline for each article page.'),
'#default_value' => $content_headline ? $content_headline : '',
'#attributes' => [
'placeholder' => '[node:title]',
],
];
// Add an option to set the author on AMP pages.
$content_author = $amp_metadata
->getContentAuthorToken();
$form['content_group']['amp_content_author'] = [
'#type' => 'textfield',
'#title' => t('Author name'),
'#description' => t('The name of the author to use on AMP pages. Use tokens to provide the correct author for each article page. Token output should be text only, no HTML markup.'),
'#default_value' => $content_author ? $content_author : '',
'#attributes' => [
'placeholder' => '[node:author:display-name]',
],
];
// Add an option to set the description on AMP pages.
$content_description = $amp_metadata
->getContentDescriptionToken();
$form['content_group']['amp_content_description'] = [
'#type' => 'textfield',
'#title' => t('Article description'),
'#description' => t('A short description of an AMP article, using fewer than 150 characters and no HTML markup. Use tokens to provide the correct description for each article page.'),
'#default_value' => $content_description ? $content_description : '',
'#attributes' => [
'placeholder' => '[node:summary]',
],
];
// Add an option to set the image on AMP pages.
$top_stories_image_guidelines_url = Url::fromUri('https://developers.google.com/search/docs/data-types/articles#article_types');
$content_image = $amp_metadata
->getContentImageToken();
$form['content_group']['amp_content_image'] = [
'#type' => 'textfield',
'#title' => t('Article image for carousel'),
'#description' => t('An article image to appear in the Top Stories carousel. Images must be at least 696px wide: refer to <a href=":image_guidelines">article image guidelines</a> for further details. Use tokens to provide the correct image for each article page.', [
':image_guidelines' => $top_stories_image_guidelines_url
->toString(),
]),
'#default_value' => $content_image ? $content_image : '',
'#attributes' => [
'placeholder' => '[node:field_image]',
],
];
// Add an option to select an image style for the organization logo.
$content_image_style = $amp_metadata
->getContentImageStyleId();
$form['content_group']['amp_content_image_style_id'] = [
'#type' => 'select',
'#title' => t('Article image style'),
'#options' => image_style_options(TRUE),
'#description' => t('The image style to use for the article image'),
'#default_value' => $content_image_style ? $content_image_style : '',
];
// Add the token browser for ease in selecting token values.
$form['content_group']['token_link'] = [
'#theme' => 'token_tree_link',
'#token_types' => 'all',
'#global_types' => TRUE,
'#click_insert' => TRUE,
'#show_restricted' => FALSE,
'#recursion_limit' => 3,
'#text' => t('Browse available tokens'),
];
return $form;
}
/**
* {@inheritdoc}
*/
public function save(array $form, FormStateInterface $form_state) {
/** @var AmpMetadata $amp_metadata */
$amp_metadata = $this->entity;
$this->tagInvalidate
->invalidateTags([
'amp_metadata',
]);
if ($amp_metadata
->isNew()) {
if (!$this->ampMetadataInfo
->ampMetadataHasGlobal()) {
$amp_metadata
->setGlobal();
$amp_metadata
->set('id', 'global');
$amp_metadata
->set('label', $this
->t('Global settings for AMP metadata'));
}
else {
$node_type = $form_state
->getValue('node_type');
$amp_metadata
->setNodeType($node_type);
$amp_metadata
->set('id', $node_type);
$amp_metadata
->set('label', $this
->t('@type settings for AMP metadata', [
'@type' => $this->entityTypeManager
->getStorage('node_type')
->load($node_type)
->label(),
]));
}
$this->tagInvalidate
->invalidateTags([
'amp_available_metadata',
]);
}
// Save organization name.
$amp_metadata
->setOrganizationName($form_state
->getValue('amp_organization_name'));
// Get file IDs of the currently uploaded logo as well as the previously
// uploaded logo.
$logo_fid_new = '';
$logo_value_new = $form_state
->getValue('amp_organization_logo_fid_new');
if (!empty($logo_value_new) && isset($logo_value_new[0])) {
$logo_fid_new = $logo_value_new[0];
}
$logo_fid_previous = '';
$logo_value_previous = $form_state
->getValue('amp_organization_logo_fid_previous');
if (!empty($logo_value_previous) && isset($logo_value_previous[0])) {
$logo_fid_previous = $logo_value_previous[0];
}
// Save new organization logo.
/** @var \Drupal\file\FileInterface $logo_file_new */
if (!empty($logo_fid_new) && !empty($logo_file_new = File::load($logo_fid_new))) {
$logo_file_new
->setPermanent();
$logo_file_new
->save();
// File usage requires an entity type and entity ID. Those don't exist
// for simple configuration: we use organization and the fid for those
// items. This causes an error if you go to the file usage page, as the
// organization entity type does not exist. Life is full of hard choices
// like this. Alternative is using config entity, which seems unwieldy.
$this->fileUsage
->add($logo_file_new, 'amp', 'amp_metadata', $amp_metadata
->get('id'));
$amp_metadata
->setOrganizationLogoFid($logo_fid_new);
}
// If no file ID is set for the logo but a value previously existed, or if
// the new file ID does not match the previous file ID, then the previous
// file needs to be removed. Delete the previous logo file.
/** @var \Drupal\file\FileInterface $logo_file_previous */
if (!empty($logo_fid_previous) && $logo_fid_previous !== $logo_fid_new && !empty($logo_file_previous = File::load($logo_fid_previous))) {
$this->fileUsage
->delete($logo_file_previous, 'amp', 'amp_metadata', $amp_metadata
->get('id'));
// Only delete the file if this is the only place it was in use.
if (empty($this->fileUsage
->listUsage($logo_file_previous))) {
$logo_file_previous
->setTemporary();
$logo_file_previous
->delete();
}
$amp_metadata
->setOrganizationLogoFid(NULL);
}
$amp_metadata
->setOrganizationLogoImageStyleId($form_state
->getValue('amp_organization_logo_image_style_id'));
// Save content settings.
$amp_metadata
->setContentSchemaType($form_state
->getValue('amp_content_schema_type'));
$amp_metadata
->setContentHeadlineToken($form_state
->getValue('amp_content_headline'));
$amp_metadata
->setContentAuthorToken($form_state
->getValue('amp_content_author'));
$amp_metadata
->setContentDescriptionToken($form_state
->getValue('amp_content_description'));
$amp_metadata
->setContentImageToken($form_state
->getValue('amp_content_image'));
$amp_metadata
->setContentImageStyleId($form_state
->getValue('amp_content_image_style_id'));
// Save the metadata and set a message about saving the data.
$status = $amp_metadata
->save();
$action = $status == SAVED_UPDATED ? 'Updated' : 'Created';
if ($amp_metadata
->isGlobal()) {
drupal_set_message($this
->t('@action the global settings for AMP Metadata.', [
'@action' => $action,
]));
}
else {
drupal_set_message($this
->t('@action the @type settings for AMP Metadata.', [
'@action' => $action,
'@type' => $this->entityTypeManager
->getStorage('node_type')
->load($amp_metadata
->getNodeType())
->label(),
]));
}
$form_state
->setRedirectUrl($amp_metadata
->urlInfo('collection'));
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
AmpMetadataForm:: |
protected | property | The AMP metadata info service. | |
AmpMetadataForm:: |
protected | property | The container. | |
AmpMetadataForm:: |
protected | property | The file usage service. | |
AmpMetadataForm:: |
protected | property |
The module handler. Overrides EntityForm:: |
|
AmpMetadataForm:: |
protected | property | The cache tags invalidator. | |
AmpMetadataForm:: |
public static | function |
Instantiates a new instance of this class. Overrides FormBase:: |
|
AmpMetadataForm:: |
public | function |
Gets the actual form array to be built. Overrides EntityForm:: |
|
AmpMetadataForm:: |
public | function |
Form submission handler for the 'save' action. Overrides EntityForm:: |
|
AmpMetadataForm:: |
public | function | Sets the Container. | |
AmpMetadataForm:: |
public | function | Constructs a AmpMetadataForm object. | |
DependencySerializationTrait:: |
protected | property | An array of entity type IDs keyed by the property name of their storages. | |
DependencySerializationTrait:: |
protected | property | An array of service IDs keyed by property name used for serialization. | |
DependencySerializationTrait:: |
public | function | 1 | |
DependencySerializationTrait:: |
public | function | 2 | |
EntityForm:: |
protected | property | The entity being used by this form. | 7 |
EntityForm:: |
protected | property | The entity type manager. | 3 |
EntityForm:: |
protected | property | The name of the current operation. | |
EntityForm:: |
private | property | The entity manager. | |
EntityForm:: |
protected | function | Returns an array of supported actions for the current entity form. | 29 |
EntityForm:: |
protected | function | Returns the action form element for the current entity form. | |
EntityForm:: |
public | function | Form element #after_build callback: Updates the entity with submitted data. | |
EntityForm:: |
public | function |
Builds an updated entity object based upon the submitted form values. Overrides EntityFormInterface:: |
2 |
EntityForm:: |
public | function |
Form constructor. Overrides FormInterface:: |
10 |
EntityForm:: |
protected | function | Copies top-level form values to entity properties | 7 |
EntityForm:: |
public | function |
Returns a string identifying the base form. Overrides BaseFormIdInterface:: |
5 |
EntityForm:: |
public | function |
Gets the form entity. Overrides EntityFormInterface:: |
|
EntityForm:: |
public | function |
Determines which entity will be used by this form from a RouteMatch object. Overrides EntityFormInterface:: |
1 |
EntityForm:: |
public | function |
Returns a unique string identifying the form. Overrides FormInterface:: |
10 |
EntityForm:: |
public | function |
Gets the operation identifying the form. Overrides EntityFormInterface:: |
|
EntityForm:: |
protected | function | Initialize the form state and the entity before the first form build. | 3 |
EntityForm:: |
protected | function | Prepares the entity object before the form is built first. | 3 |
EntityForm:: |
protected | function | Invokes the specified prepare hook variant. | |
EntityForm:: |
public | function | Process callback: assigns weights and hides extra fields. | |
EntityForm:: |
public | function |
Sets the form entity. Overrides EntityFormInterface:: |
|
EntityForm:: |
public | function |
Sets the entity manager for this form. Overrides EntityFormInterface:: |
|
EntityForm:: |
public | function |
Sets the entity type manager for this form. Overrides EntityFormInterface:: |
|
EntityForm:: |
public | function |
Sets the module handler for this form. Overrides EntityFormInterface:: |
|
EntityForm:: |
public | function |
Sets the operation for this form. Overrides EntityFormInterface:: |
|
EntityForm:: |
public | function |
This is the default entity object builder function. It is called before any
other submit handler to build the new entity object to be used by the
following submit handlers. At this point of the form workflow the entity is
validated and the form state… Overrides FormInterface:: |
17 |
EntityForm:: |
public | function | ||
EntityForm:: |
public | function | ||
FormBase:: |
protected | property | The config factory. | 1 |
FormBase:: |
protected | property | The request stack. | 1 |
FormBase:: |
protected | property | The route match. | |
FormBase:: |
protected | function | Retrieves a configuration object. | |
FormBase:: |
protected | function | Gets the config factory for this form. | 1 |
FormBase:: |
private | function | Returns the service container. | |
FormBase:: |
protected | function | Gets the current user. | |
FormBase:: |
protected | function | Gets the request object. | |
FormBase:: |
protected | function | Gets the route match. | |
FormBase:: |
protected | function | Gets the logger for a specific channel. | |
FormBase:: |
protected | function |
Returns a redirect response object for the specified route. Overrides UrlGeneratorTrait:: |
|
FormBase:: |
public | function | Resets the configuration factory. | |
FormBase:: |
public | function | Sets the config factory for this form. | |
FormBase:: |
public | function | Sets the request stack object to use. | |
FormBase:: |
public | function |
Form validation handler. Overrides FormInterface:: |
62 |
LinkGeneratorTrait:: |
protected | property | The link generator. | 1 |
LinkGeneratorTrait:: |
protected | function | Returns the link generator. | |
LinkGeneratorTrait:: |
protected | function | Renders a link to a route given a route name and its parameters. | |
LinkGeneratorTrait:: |
public | function | Sets the link generator service. | |
LoggerChannelTrait:: |
protected | property | The logger channel factory service. | |
LoggerChannelTrait:: |
protected | function | Gets the logger for a specific channel. | |
LoggerChannelTrait:: |
public | function | Injects the logger channel factory. | |
MessengerTrait:: |
protected | property | The messenger. | 29 |
MessengerTrait:: |
public | function | Gets the messenger. | 29 |
MessengerTrait:: |
public | function | Sets the messenger. | |
RedirectDestinationTrait:: |
protected | property | The redirect destination service. | 1 |
RedirectDestinationTrait:: |
protected | function | Prepares a 'destination' URL query parameter for use with \Drupal\Core\Url. | |
RedirectDestinationTrait:: |
protected | function | Returns the redirect destination service. | |
RedirectDestinationTrait:: |
public | function | Sets the redirect destination service. | |
StringTranslationTrait:: |
protected | property | The string translation service. | 1 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. | |
UrlGeneratorTrait:: |
protected | property | The url generator. | |
UrlGeneratorTrait:: |
protected | function | Returns the URL generator service. | |
UrlGeneratorTrait:: |
public | function | Sets the URL generator service. | |
UrlGeneratorTrait:: |
protected | function | Generates a URL or path for a specific route based on the given parameters. |