dynamic_image_generator-1.0.x-dev/src/Form/DynamicImageGeneratorSettingsForm.php

src/Form/DynamicImageGeneratorSettingsForm.php
<?php

// File: src/Form/DynamicImageGeneratorSettingsForm.php

namespace Drupal\dynamic_image_generator\Form;

use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use GuzzleHttp\ClientInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;

/**
 * Configure Dynamic Image Generator API settings.
 * 
 * This form handles API configuration, different from ImageTemplateSettingsForm
 * which handles template entity settings.
 */
class DynamicImageGeneratorSettingsForm extends ConfigFormBase {

  /**
   * The HTTP client.
   *
   * @var \GuzzleHttp\ClientInterface
   */
  protected $httpClient;

  /**
   * The messenger service.
   *
   * @var \Drupal\Core\Messenger\MessengerInterface
   */
  protected $messenger;

  /**
   * The logger service.
   *
   * @var \Psr\Log\LoggerInterface
   */
  protected $logger;

  /**
   * Constructs a DynamicImageGeneratorSettingsForm object.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The factory for configuration objects.
   * @param \GuzzleHttp\ClientInterface $http_client
   *   The HTTP client.
   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
   *   The messenger service.
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
   *   The logger factory service.
   */
  public function __construct(ConfigFactoryInterface $config_factory, ClientInterface $http_client, MessengerInterface $messenger, LoggerChannelFactoryInterface $logger_factory) {
    parent::__construct($config_factory);
    $this->httpClient = $http_client;
    $this->messenger = $messenger;
    $this->logger = $logger_factory->get('dynamic_image_generator');
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('config.factory'),
      $container->get('http_client'),
      $container->get('messenger'),
      $container->get('logger.factory')
    );
  }

  /**
   * {@inheritdoc}
   */
  protected function getEditableConfigNames() {
    return ['dynamic_image_generator.settings'];
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'dynamic_image_generator_api_settings_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $config = $this->config('dynamic_image_generator.settings');

    // Page header
    $form['header'] = [
      '#type' => 'markup',
      '#markup' => '<div class="image-settings-header">
        <h2>Dynamic Image Generator API Settings</h2>
        <p>Configure your image generation API credentials and settings.</p>
      </div>',
    ];

    // API Configuration Section
    $form['api_settings'] = [
      '#type' => 'details',
      '#title' => $this->t('API Configuration'),
      '#open' => TRUE,
      '#description' => $this->t('Configure your HTML/CSS to Image API credentials. Get your credentials from <a href="@url" target="_blank">htmlcsstoimage.com dashboard</a>.', [
        '@url' => 'https://htmlcsstoimage.com/dashboard',
      ]),
    ];

    // API provider selection - only show built-in if module is available
    $api_provider_options = [
      'htmlcsstoimage' => $this->t('External API (htmlcsstoimage.com)'),
    ];
    
    // Only add built-in option if the image_creating_engine module is enabled
    if (\Drupal::moduleHandler()->moduleExists('image_creating_engine')) {
      $api_provider_options['inbuilt'] = $this->t('Built-in Image Engine (Local)');
    }

    $form['api_settings']['api_provider'] = [
      '#type' => 'radios',
      '#title' => $this->t('Image Generation Provider'),
      '#description' => $this->t('Choose how images should be generated.'),
      '#options' => $api_provider_options,
      '#default_value' => $config->get('api_provider') ?: 'htmlcsstoimage',
      '#required' => TRUE,
      '#ajax' => [
        'callback' => [$this, 'updateApiFieldsCallback'],
        'wrapper' => 'api-credentials-wrapper',
        'event' => 'change',
      ],
    ];

    // Get the currently selected API provider
    $selected_provider = $form_state->getValue('api_provider') ?: $config->get('api_provider') ?: 'htmlcsstoimage';

    // Wrap API credential fields in a container for AJAX updating
    $form['api_settings']['credentials_wrapper'] = [
      '#type' => 'container',
      '#attributes' => ['id' => 'api-credentials-wrapper'],
    ];

    // Change required state based on selected provider
    $api_fields_required = ($selected_provider === 'htmlcsstoimage');
    
    $form['api_settings']['credentials_wrapper']['api_user_id'] = [
      '#type' => 'textfield',
      '#title' => $this->t('API User ID'),
      '#description' => $this->t('Your API User ID from htmlcsstoimage.com dashboard.'),
      '#default_value' => $config->get('api_user_id'),
      '#required' => $api_fields_required,
      '#size' => 60,
      '#maxlength' => 255,
      '#placeholder' => 'e.g., sadd-c7b0-4daf-a46b-sadasdade',
      '#states' => [
        'visible' => [
          ':input[name="api_provider"]' => ['value' => 'htmlcsstoimage'],
        ],
        'required' => [
          ':input[name="api_provider"]' => ['value' => 'htmlcsstoimage'],
        ],
      ],
    ];

    $form['api_settings']['credentials_wrapper']['api_key'] = [
      '#type' => 'password',
      '#title' => $this->t('API Key'),
      '#description' => $this->t('Your API Key from htmlcsstoimage.com dashboard. Leave blank to keep current key.'),
      '#size' => 60,
      '#maxlength' => 255,
      '#placeholder' => 'Enter your API key here...',
      '#states' => [
        'visible' => [
          ':input[name="api_provider"]' => ['value' => 'htmlcsstoimage'],
        ],
      ],
    ];

    // Show current API key status
    if ($config->get('api_key')) {
      $form['api_settings']['credentials_wrapper']['current_key_status'] = [
        '#type' => 'markup',
        '#markup' => '<div class="messages messages--status">
          <strong>API Key Status:</strong> Currently configured (last 8 characters: ••••••••' . substr($config->get('api_key'), -8) . ')
          <br><small>Enter a new key above to update it, or leave blank to keep the current key.</small>
        </div>',
        '#states' => [
          'visible' => [
            ':input[name="api_provider"]' => ['value' => 'htmlcsstoimage'],
          ],
        ],
      ];
    }

    $form['api_settings']['credentials_wrapper']['api_endpoint'] = [
      '#type' => 'url',
      '#title' => $this->t('API Endpoint'),
      '#description' => $this->t('The API endpoint URL. Usually you don\'t need to change this.'),
      '#default_value' => $config->get('api_endpoint') ?: 'https://hcti.io/v1/image',
      '#required' => $api_fields_required,
      '#size' => 80,
      '#states' => [
        'visible' => [
          ':input[name="api_provider"]' => ['value' => 'htmlcsstoimage'],
        ],
        'required' => [
          ':input[name="api_provider"]' => ['value' => 'htmlcsstoimage'],
        ],
      ],
    ];

    // Add a message explaining the built-in engine when selected
    $form['api_settings']['credentials_wrapper']['inbuilt_info'] = [
      '#type' => 'markup',
      '#markup' => '<div class="messages messages--info">
        <strong>Built-in Engine:</strong> This option uses wkhtmltoimage to generate images locally without requiring external API credentials. 
        <br><small>Note: The built-in engine provides fast, reliable HTML/CSS rendering directly on your server. Requires wkhtmltopdf package (sudo apt-get install wkhtmltopdf).</small>
      </div>',
      '#states' => [
        'visible' => [
          ':input[name="api_provider"]' => ['value' => 'inbuilt'],
        ],
      ],
    ];

    // Add a test button for each provider
    $form['api_settings']['credentials_wrapper']['test_container'] = [
      '#type' => 'container',
      '#attributes' => ['class' => ['api-test-container']],
    ];

    // For htmlcsstoimage provider
    $form['api_settings']['credentials_wrapper']['test_container']['test_htmlcsstoimage'] = [
      '#type' => 'button',
      '#value' => $this->t('Test API Connection'),
      '#ajax' => [
        'callback' => [$this, 'testApiConnectionCallback'],
        'wrapper' => 'api-test-result',
        'progress' => ['type' => 'throbber', 'message' => 'Testing connection...'],
      ],
      '#states' => [
        'visible' => [
          ':input[name="api_provider"]' => ['value' => 'htmlcsstoimage'],
        ],
      ],
    ];

    // For inbuilt provider - fix the button so it doesn't disappear
    $form['api_settings']['credentials_wrapper']['test_container']['test_inbuilt'] = [
      '#type' => 'button',
      '#value' => $this->t('Test Built-in Generator'),
      '#ajax' => [
        'callback' => [$this, 'testInbuiltGeneratorCallback'],
        'wrapper' => 'api-test-result',
        'progress' => ['type' => 'throbber', 'message' => 'Testing built-in generator...'],
      ],
      '#states' => [
        'visible' => [
          ':input[name="api_provider"]' => ['value' => 'inbuilt'],
        ],
      ],
    ];

    // Container for test results
    $form['api_settings']['credentials_wrapper']['test_result'] = [
      '#type' => 'container',
      '#attributes' => ['id' => 'api-test-result'],
    ];

    /*
    // Image Generation Settings
    $form['generation_settings'] = [
      '#type' => 'details',
      '#title' => $this->t('Image Generation Settings'),
      '#open' => TRUE,
      '#description' => $this->t('Configure default settings for generated images.'),
    ];

    $form['generation_settings']['default_width'] = [
      '#type' => 'number',
      '#title' => $this->t('Default Width'),
      '#description' => $this->t('Default width for generated images in pixels.'),
      '#default_value' => $config->get('default_width') ?: 1200,
      '#required' => TRUE,
      '#min' => 100,
      '#max' => 3000,
      '#step' => 1,
    ];

    $form['generation_settings']['default_height'] = [
      '#type' => 'number',
      '#title' => $this->t('Default Height'),
      '#description' => $this->t('Default height for generated images in pixels.'),
      '#default_value' => $config->get('default_height') ?: 630,
      '#required' => TRUE,
      '#min' => 100,
      '#max' => 3000,
      '#step' => 1,
    ];

    $form['generation_settings']['image_format'] = [
      '#type' => 'select',
      '#title' => $this->t('Image Format'),
      '#description' => $this->t('The default image format for generated images.'),
      '#options' => [
        'png' => $this->t('PNG (better quality, larger file size)'),
        'jpeg' => $this->t('JPEG (smaller file size, lossy compression)'),
      ],
      '#default_value' => $config->get('image_format') ?: 'png',
      '#required' => TRUE,
    ];

    $form['generation_settings']['quality'] = [
      '#type' => 'number',
      '#title' => $this->t('Image Quality'),
      '#description' => $this->t('Quality setting for JPEG images (0-100). Higher values mean better quality but larger file size.'),
      '#default_value' => $config->get('quality') ?: 90,
      '#required' => TRUE,
      '#min' => 10,
      '#max' => 100,
      '#step' => 1,
      '#states' => [
        'visible' => [
          ':input[name="image_format"]' => ['value' => 'jpeg'],
        ],
      ],
    ];
    */

    // Advanced Settings
    $form['advanced_settings'] = [
      '#type' => 'details',
      '#title' => $this->t('Advanced Settings'),
      '#open' => FALSE,
    ];

    $form['advanced_settings']['debug_mode'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Enable Debug Mode'),
      '#description' => $this->t('When enabled, additional debug information will be logged during image generation.'),
      '#default_value' => $config->get('debug_mode') ?: FALSE,
    ];

    // Add submit button
    $form['actions'] = [
      '#type' => 'actions',
    ];
    
    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Save Settings'),
      '#button_type' => 'primary',
    ];

    return parent::buildForm($form, $form_state);
  }

  /**
   * Ajax callback to update API credential fields.
   */
  public function updateApiFieldsCallback(array &$form, FormStateInterface $form_state) {
    // Get the selected provider from form state
    $selected_provider = $form_state->getValue('api_provider');
    
    // Manually set access based on provider selection instead of relying on #states
    if ($selected_provider === 'htmlcsstoimage') {
      $form['api_settings']['credentials_wrapper']['api_user_id']['#access'] = TRUE;
      $form['api_settings']['credentials_wrapper']['api_key']['#access'] = TRUE;
      $form['api_settings']['credentials_wrapper']['api_endpoint']['#access'] = TRUE;
      if (isset($form['api_settings']['credentials_wrapper']['current_key_status'])) {
        $form['api_settings']['credentials_wrapper']['current_key_status']['#access'] = TRUE;
      }
      $form['api_settings']['credentials_wrapper']['inbuilt_info']['#access'] = FALSE;
      $form['api_settings']['credentials_wrapper']['test_container']['test_htmlcsstoimage']['#access'] = TRUE;
      $form['api_settings']['credentials_wrapper']['test_container']['test_inbuilt']['#access'] = FALSE;
    } else {
      $form['api_settings']['credentials_wrapper']['api_user_id']['#access'] = FALSE;
      $form['api_settings']['credentials_wrapper']['api_key']['#access'] = FALSE;
      $form['api_settings']['credentials_wrapper']['api_endpoint']['#access'] = FALSE;
      if (isset($form['api_settings']['credentials_wrapper']['current_key_status'])) {
        $form['api_settings']['credentials_wrapper']['current_key_status']['#access'] = FALSE;
      }
      $form['api_settings']['credentials_wrapper']['inbuilt_info']['#access'] = TRUE;
      $form['api_settings']['credentials_wrapper']['test_container']['test_htmlcsstoimage']['#access'] = FALSE;
      $form['api_settings']['credentials_wrapper']['test_container']['test_inbuilt']['#access'] = TRUE;
    }
    
    return $form['api_settings']['credentials_wrapper'];
  }

  /**
   * Ajax callback to test API connection.
   */
  public function testApiConnectionCallback(array &$form, FormStateInterface $form_state) {
    $user_id = $form_state->getValue('api_user_id');
    $api_key = $form_state->getValue('api_key') ?: $this->config('dynamic_image_generator.settings')->get('api_key');
    $endpoint = $form_state->getValue('api_endpoint');
    
    $response = ['#markup' => ''];
    
    if (empty($user_id) || empty($api_key) || empty($endpoint)) {
      $response['#markup'] = '<div class="messages messages--error">Please provide API credentials before testing.</div>';
      return $response;
    }
    
    try {
      $test_data = [
        'html' => '<div style="width: 300px; height: 150px; background: #007bff; color: white; display: flex; align-items: center; justify-content: center; font-family: Arial; font-size: 24px; font-weight: bold;">API Test Success</div>',
        'css' => 'body { margin: 0; padding: 20px; }',
        'width' => 340,
        'height' => 190,
      ];

      $api_response = $this->httpClient->request('POST', $endpoint, [
        'form_params' => $test_data,
        'auth' => [$user_id, $api_key],
        'timeout' => 30,
      ]);

      if ($api_response->getStatusCode() === 200) {
        $result = json_decode($api_response->getBody(), TRUE);
        if (!empty($result['url'])) {
          $response['#markup'] = '<div class="messages messages--status">
            <strong>API Connection Successful!</strong><br>
            <img src="' . $result['url'] . '" alt="Test image" style="max-width: 100%; margin-top: 10px; border: 1px solid #ddd; border-radius: 4px;">
          </div>';
        } else {
          $response['#markup'] = '<div class="messages messages--warning">
            <strong>Partial Success:</strong> Connected to API but no image URL was returned.
          </div>';
        }
      } else {
        $response['#markup'] = '<div class="messages messages--error">
          <strong>API Connection Failed:</strong> Unexpected response code: ' . $api_response->getStatusCode() . '
        </div>';
      }
    } catch (\Exception $e) {
      $response['#markup'] = '<div class="messages messages--error">
        <strong>API Connection Failed:</strong> ' . $e->getMessage() . '
      </div>';
    }
    
    return $response;
  }

  /**
   * Ajax callback to test the built-in generator.
   */
  public function testInbuiltGeneratorCallback(array &$form, FormStateInterface $form_state) {
    $response = ['#markup' => ''];
    
    try {
      // Check if we have the inbuilt service
      if (!\Drupal::hasService('image_creating_engine.generator')) {
        // Change the error message to be more helpful
        $response['#markup'] = '<div class="messages messages--error">
          <strong>Built-in Generator Error:</strong> The image_creating_engine module is not enabled. 
          Please enable it first by going to Extend page and enabling "Image Creating Engine" module.
        </div>';
        return $response;
      }
      
      // Get the inbuilt generator service
      $generator = \Drupal::service('image_creating_engine.generator');
      
      // Simple test HTML and CSS
      $test_html = '<div class="test-image">Built-in Generator Works!</div>';
      $test_css = 'body { margin: 0; padding: 20px; background: #f5f5f5; }
        .test-image { 
          width: 300px; 
          height: 150px; 
          background: #28a745; 
          color: white; 
          display: flex; 
          align-items: center; 
          justify-content: center; 
          font-family: Arial, sans-serif; 
          font-size: 20px; 
          font-weight: bold;
          border-radius: 8px;
        }';
      
      $options = [
        'width' => 340,
        'height' => 190,
        'format' => 'png',
      ];
      
      // Generate a test image
      $result = $generator->generateImage($test_html, $test_css, $options);
      $image_url = $result['url'];

      if ($image_url) {
        $response['#markup'] = '<div class="messages messages--status">
          <strong>Built-in Generator is Working!</strong><br>
          <img src="' . $image_url . '" alt="Test image" style="max-width: 100%; margin-top: 10px; border: 1px solid #ddd; border-radius: 4px;">
        </div>';
      } else {
        $response['#markup'] = '<div class="messages messages--error">
          <strong>Built-in Generator Failed:</strong> Could not generate test image. Check logs for details.
        </div>';
      }
    } catch (\Exception $e) {
      $response['#markup'] = '<div class="messages messages--error">
        <strong>Built-in Generator Error:</strong> ' . $e->getMessage() . '
      </div>';
    }
    
    return $response;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    $values = $form_state->getValues();
    $api_provider = $values['api_provider'];

    // Only validate API credentials if using external API
    if ($api_provider === 'htmlcsstoimage') {
      // Check if API User ID is provided
      if (empty($values['api_user_id'])) {
        $form_state->setErrorByName('api_user_id', $this->t('API User ID is required when using the external API.'));
      }

      // Check if we need a new API key
      $config = $this->config('dynamic_image_generator.settings');
      $current_api_key = $config->get('api_key');
      
      // If API key field is empty and we don't have an existing key, show error
      if (empty($values['api_key']) && empty($current_api_key)) {
        $form_state->setErrorByName('api_key', $this->t('API Key is required when using the external API.'));
      }
      
      // Validate API endpoint URL
      if (empty($values['api_endpoint'])) {
        $form_state->setErrorByName('api_endpoint', $this->t('API Endpoint URL is required when using the external API.'));
      }
    }
    
    // Validate other form fields regardless of API provider
    parent::validateForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $config = $this->config('dynamic_image_generator.settings');
    $values = $form_state->getValues();
    
    // Save API provider selection
    $config->set('api_provider', $values['api_provider']);
    
    // Only save API credentials if using external API
    if ($values['api_provider'] === 'htmlcsstoimage') {
      $config->set('api_user_id', $values['api_user_id']);
      
      // Only update API key if a new one was provided
      if (!empty($values['api_key'])) {
        $config->set('api_key', $values['api_key']);
      }
      
      $config->set('api_endpoint', $values['api_endpoint']);
    }
    
    // Remove the commented out generation settings from being saved
    // since they're commented out in the form
    // $config->set('default_width', $values['default_width']);
    // $config->set('default_height', $values['default_height']);
    // $config->set('image_format', $values['image_format']);
    // $config->set('quality', $values['quality']);
    
    $config->set('debug_mode', !empty($values['debug_mode']));
    
    $config->save();
    
    $this->messenger->addMessage($this->t('Dynamic Image Generator settings have been saved.'));
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc