dynamic_image_generator-1.0.x-dev/src/Controller/DynamicImageGeneratorAdminController.php
src/Controller/DynamicImageGeneratorAdminController.php
<?php
namespace Drupal\dynamic_image_generator\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Link;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
/**
* Admin controller for Poster Generator overview and management.
*/
class DynamicImageGeneratorAdminController extends ControllerBase {
/**
* The config factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* Constructs a DynamicImageGeneratorAdminController object.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*/
public function __construct(ConfigFactoryInterface $config_factory, EntityTypeManagerInterface $entity_type_manager) {
$this->configFactory = $config_factory;
$this->entityTypeManager = $entity_type_manager;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('config.factory'),
$container->get('entity_type.manager')
);
}
/**
* Dynamic Image Generator admin overview page.
*
* @return array
* A render array for the overview page.
*/
public function overview() {
$build = [];
// Page header
$build['header'] = [
'#type' => 'markup',
'#markup' => '
<div class="image-admin-header">
<h1>Dynamic Image Generator</h1>
<p>Create beautiful images from your content automatically using customizable HTML/CSS templates.</p>
</div>
',
];
// System status
$build['status'] = $this->buildStatusSection();
// Quick actions
$build['actions'] = $this->buildActionsSection();
// Getting started
$build['getting_started'] = $this->buildGettingStartedSection();
// Recent activity
$build['recent'] = $this->buildRecentActivitySection();
// Add CSS styling
$build['#attached']['html_head'][] = [
[
'#type' => 'html_tag',
'#tag' => 'style',
'#value' => '
.poster-admin-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 30px;
border-radius: 12px;
margin-bottom: 30px;
text-align: center;
}
.poster-admin-header h1 {
margin: 0 0 10px 0;
font-size: 2.5em;
font-weight: 300;
}
.poster-admin-header p {
margin: 0;
font-size: 1.2em;
opacity: 0.9;
}
.status-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.status-card {
background: white;
border: 1px solid #e1e5e9;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.status-card h3 {
margin: 0 0 10px 0;
color: #2c3e50;
font-size: 1.1em;
}
.status-indicator {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 50%;
margin-right: 8px;
}
.status-ok { background-color: #28a745; }
.status-warning { background-color: #ffc107; }
.status-error { background-color: #dc3545; }
.action-buttons {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 30px;
}
.action-button {
display: block;
padding: 15px 20px;
background: #007bff;
color: white;
text-decoration: none;
border-radius: 8px;
text-align: center;
font-weight: 500;
transition: background-color 0.2s;
}
.action-button:hover {
background: #0056b3;
color: white;
text-decoration: none;
}
.action-button.secondary {
background: #6c757d;
}
.action-button.secondary:hover {
background: #545b62;
}
.getting-started {
background: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 8px;
padding: 20px;
}
.step-list {
counter-reset: step-counter;
list-style: none;
padding: 0;
}
.step-list li {
counter-increment: step-counter;
margin-bottom: 15px;
padding-left: 40px;
position: relative;
}
.step-list li::before {
content: counter(step-counter);
position: absolute;
left: 0;
top: 0;
background: #007bff;
color: white;
width: 24px;
height: 24px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
font-weight: bold;
}
',
],
'poster_admin_overview_css',
];
return $build;
}
/**
* Build the system status section.
*
* @return array
* Status section render array.
*/
protected function buildStatusSection() {
$config = $this->configFactory->get('dynamic_image_generator.settings');
// Check API configuration
$api_configured = !empty($config->get('api_user_id')) && !empty($config->get('api_key'));
// Count templates
try {
$template_count = $this->entityTypeManager
->getStorage('poster_entity')
->getQuery()
->accessCheck(FALSE)
->count()
->execute();
} catch (\Exception $e) {
$template_count = 0;
}
// Count generated posters
try {
$poster_count = $this->entityTypeManager
->getStorage('media')
->getQuery()
->condition('bundle', 'dynamic_image')
->accessCheck(FALSE)
->count()
->execute();
} catch (\Exception $e) {
$poster_count = 0;
}
$status_items = [
[
'title' => 'API Configuration',
'status' => $api_configured ? 'ok' : 'warning',
'message' => $api_configured ? 'API credentials configured' : 'API credentials needed',
'details' => $api_configured
? 'Ready to generate posters'
: Link::createFromRoute('Configure API settings', 'dynamic_image_generator.settings')->toString(),
],
[
'title' => 'Image Templates',
'status' => $template_count > 0 ? 'ok' : 'warning',
'message' => $template_count . ' template' . ($template_count != 1 ? 's' : '') . ' created',
'details' => $template_count > 0
? Link::createFromRoute('Manage templates', 'entity.poster_entity.collection')->toString()
: Link::createFromRoute('Create your first template', 'entity.poster_entity.add_form')->toString(),
],
[
'title' => 'Generated Images',
'status' => 'ok',
'message' => $poster_count . ' image' . ($poster_count != 1 ? 's' : '') . ' generated',
'details' => $poster_count > 0
? Link::createFromRoute('View in media library', 'generated_dynamic_images.page_1')->toString()
: 'No images generated yet',
],
[
'title' => 'System Health',
'status' => 'ok',
'message' => 'All systems operational',
'details' => 'Module is ready for use',
],
];
$build = [
'#type' => 'details',
'#title' => $this->t('System Status'),
'#open' => TRUE,
];
$build['status_grid'] = [
'#type' => 'markup',
'#markup' => '<div class="status-grid">',
];
foreach ($status_items as $item) {
$status_class = 'status-' . $item['status'];
$build['status_grid']['#markup'] .= "
<div class='status-card'>
<h3>
<span class='status-indicator {$status_class}'></span>
{$item['title']}
</h3>
<div><strong>{$item['message']}</strong></div>
<div><small>{$item['details']}</small></div>
</div>
";
}
$build['status_grid']['#markup'] .= '</div>';
return $build;
}
/**
* Build the quick actions section.
*
* @return array
* Actions section render array.
*/
protected function buildActionsSection() {
$build = [
'#type' => 'details',
'#title' => $this->t('Quick Actions'),
'#open' => TRUE,
];
$build['actions'] = [
'#type' => 'container',
'#attributes' => ['class' => ['image-admin-actions']],
];
$build['actions']['title'] = [
'#type' => 'markup',
'#markup' => '<h3>Quick Actions</h3>',
];
$build['actions']['links'] = [
'#theme' => 'item_list',
'#items' => [
Link::createFromRoute('Create New Template', 'entity.poster_entity.add_form', [], [
'attributes' => ['class' => ['button', 'button--primary']],
]),
Link::createFromRoute('Manage Templates', 'entity.poster_entity.collection', [], [
'attributes' => ['class' => ['button']],
]),
Link::createFromRoute('View Generated Images', 'generated_dynamic_images.page_1', [], [
'attributes' => ['class' => ['button']],
]),
Link::createFromRoute('API Settings', 'dynamic_image_generator.settings', [], [
'attributes' => ['class' => ['button']],
]),
Link::createFromRoute('Usage Examples', 'dynamic_image_generator.example', [], [
'attributes' => ['class' => ['button']],
]),
],
'#attributes' => ['class' => ['action-links']],
];
return $build;
}
/**
* Build the getting started section.
*
* @return array
* Getting started section render array.
*/
protected function buildGettingStartedSection() {
$config = $this->configFactory->get('dynamic_image_generator.settings');
$api_configured = !empty($config->get('api_user_id')) && !empty($config->get('api_key'));
$build = [
'#type' => 'details',
'#title' => $this->t('Getting Started'),
'#open' => !$api_configured,
];
$build['content'] = [
'#type' => 'markup',
'#markup' => '
<div class="getting-started">
<h3>Follow these steps to start generating posters:</h3>
<ol class="step-list">
<li>
<strong>Configure API credentials</strong><br>
<small>Get your API key from <a href="https://htmlcsstoimage.com" target="_blank">htmlcsstoimage.com</a> and configure it in the API settings.</small>
</li>
<li>
<strong>Create a poster template</strong><br>
<small>Design your poster using HTML and CSS. Use tokens to pull content from your entities.</small>
</li>
<li>
<strong>Configure content types</strong><br>
<small>Set which content types should automatically generate posters using your templates.</small>
</li>
<li>
<strong>Test and generate</strong><br>
<small>Create or edit content to automatically generate poster images.</small>
</li>
</ol>
<h4>Need help?</h4>
<ul>
<li><a href="/admin/config/content/poster-generator/example">View template examples</a></li>
<li><a href="https://htmlcsstoimage.com/docs" target="_blank">API documentation</a></li>
<li><a href="/admin/reports/dblog?type%5B%5D=dynamic_image_generator" target="_blank">Check system logs</a></li>
</ul>
</div>
',
];
return $build;
}
/**
* Build the recent activity section.
*
* @return array
* Recent activity section render array.
*/
protected function buildRecentActivitySection() {
$build = [
'#type' => 'details',
'#title' => $this->t('Recent Activity'),
'#open' => FALSE,
];
try {
// Get recent poster media
$recent_posters = $this->entityTypeManager
->getStorage('media')
->loadByProperties([
'bundle' => 'poster',
]);
if (!empty($recent_posters)) {
// Sort by creation date
uasort($recent_posters, function($a, $b) {
return $b->getCreatedTime() - $a->getCreatedTime();
});
// Take only the 5 most recent
$recent_posters = array_slice($recent_posters, 0, 5, TRUE);
$items = [];
foreach ($recent_posters as $poster) {
$created = \Drupal::service('date.formatter')->format($poster->getCreatedTime(), 'short');
$items[] = $this->t('@name - @date', [
'@name' => $poster->getName(),
'@date' => $created,
]);
}
$build['list'] = [
'#theme' => 'item_list',
'#title' => $this->t('Recently generated posters:'),
'#items' => $items,
];
} else {
$build['empty'] = [
'#type' => 'markup',
'#markup' => '<p>No posters have been generated yet. ' .
Link::createFromRoute('Create your first template', 'entity.poster_entity.add_form')->toString() .
' to get started.</p>',
];
}
} catch (\Exception $e) {
$build['error'] = [
'#type' => 'markup',
'#markup' => '<p>Unable to load recent activity.</p>',
];
}
return $build;
}
/**
* Test Built-in Image Generator.
*
* @return array
* Render array containing the result of the test.
*/
public function testBuiltInGenerator() {
$generator = \Drupal::service('image_creating_engine.generator');
$test_html = '<div style="background: linear-gradient(45deg, #4CAF50, #45a049); color: white; padding: 30px; text-align: center; border-radius: 10px; font-family: Arial, sans-serif;"><h2 style="margin: 0 0 10px 0;">Built-in Generator Test</h2><p style="margin: 0;">Generated at ' . date('Y-m-d H:i:s') . '</p></div>';
$test_css = 'body { margin: 0; padding: 20px; background: #f5f5f5; }';
$result = $generator->generateImage($test_html, $test_css, [
'width' => 500,
'height' => 200,
'format' => 'png'
]);
if ($result && isset($result['url'])) {
$build['success'] = [
'#markup' => '<div class="messages messages--status">
<strong>Built-in Generator is Working!</strong><br>
<img src="' . $result['url'] . '" alt="Test image" style="max-width: 100%; border: 1px solid #ddd; margin-top: 10px;">
</div>',
];
} else {
$build['error'] = [
'#markup' => '<div class="messages messages--error">
<strong>Built-in Generator Failed!</strong><br>
Could not generate test image.
</div>',
];
}
return $build;
}
}