Created
August 12, 2022 13:38
-
-
Save devudit/04d0430b48462ad201de8ce05a208085 to your computer and use it in GitHub Desktop.
Feeds Fetcher — Drupal
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Defines a sftp fetcher. | |
* | |
* @FeedsFetcher( | |
* id = "sftp_fetcher", | |
* title = @Translation("Sftp Fetcher"), | |
* description = @Translation("Use file on a remote server."), | |
* form = { | |
* "configuration" = "Drupal\feeds_sftp_fetcher\Feeds\Fetcher\Form\SftpFetcherForm", | |
* "feed" = "\Drupal\feeds_sftp_fetcher\Feeds\Fetcher\Form\SftpFetcherFeedForm", | |
* }, | |
* ) | |
*/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Drupal\feeds_sftp_fetcher\Feeds\Fetcher; | |
use Drupal\Core\File\FileSystemInterface; | |
use Drupal\Core\Logger\LoggerChannelFactoryInterface; | |
use Drupal\Core\Plugin\ContainerFactoryPluginInterface; | |
use Drupal\Core\Utility\Token; | |
use Drupal\feeds\Exception\EmptyFeedException; | |
use Drupal\feeds\FeedInterface; | |
use Drupal\feeds\Plugin\Type\Fetcher\FetcherInterface; | |
use Drupal\feeds\Plugin\Type\PluginBase; | |
use Drupal\feeds\Result\FetcherResult; | |
use Drupal\feeds\StateInterface; | |
use Drupal\feeds\Utility\File; | |
use phpseclib3\Net\SFTP; | |
use Symfony\Component\DependencyInjection\ContainerInterface; | |
/** | |
* Defines a sftp fetcher. | |
* | |
* @FeedsFetcher( | |
* id = "sftp_fetcher", | |
* title = @Translation("Sftp Fetcher"), | |
* description = @Translation("Use file on a remote server."), | |
* form = { | |
* "configuration" = | |
* "Drupal\feeds_sftp_fetcher\Feeds\Fetcher\Form\SftpFetcherForm", | |
* "feed" = | |
* "\Drupal\feeds_sftp_fetcher\Feeds\Fetcher\Form\SftpFetcherFeedForm", | |
* }, | |
* ) | |
*/ | |
class SftpFetcher extends PluginBase implements FetcherInterface, ContainerFactoryPluginInterface { | |
/** | |
* File system object. | |
* | |
* @var \Drupal\Core\File\FileSystemInterface | |
*/ | |
protected $fileSystem; | |
/** | |
* Logger channel factory object. | |
* | |
* @var \Drupal\Core\Logger\LoggerChannelInterface | |
*/ | |
protected $logger; | |
/** | |
* Drupal token. | |
* | |
* @var \Drupal\Core\Utility\Token | |
*/ | |
protected $token; | |
/** | |
* Constructs an UploadFetcher object. | |
* | |
* @param array $configuration | |
* The plugin configuration. | |
* @param string $plugin_id | |
* The plugin id. | |
* @param array $plugin_definition | |
* The plugin definition. | |
* @param \Drupal\Core\File\FileSystemInterface $fileSystem | |
* File system service. | |
* @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $loggerChannelFactory | |
* Logger service. | |
* @param \Drupal\Core\Utility\Token $token | |
* Token replacement utility. | |
*/ | |
public function __construct(array $configuration, $plugin_id, array $plugin_definition, | |
FileSystemInterface $fileSystem, | |
LoggerChannelFactoryInterface $loggerChannelFactory, | |
Token $token) { | |
$this->fileSystem = $fileSystem; | |
$this->logger = $loggerChannelFactory->get('feeds_sftp_fetcher'); | |
$this->token = $token; | |
parent::__construct($configuration, $plugin_id, $plugin_definition); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { | |
return new static( | |
$configuration, | |
$plugin_id, | |
$plugin_definition, | |
$container->get('file_system'), | |
$container->get('logger.factory'), | |
$container->get('token') | |
); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function fetch(FeedInterface $feed, StateInterface $state) { | |
$path = $this->getFileFromSftp($feed, $state); | |
// Just return a file fetcher result if this is a file. Make sure to | |
// re-validate the file extension in case the feed type settings have | |
// changed. | |
if (is_file($path)) { | |
if (File::validateExtension($path, $this->configuration['allowed_extensions'])) { | |
return new FetcherResult($path); | |
} | |
else { | |
throw new \RuntimeException($this->t('%source has an invalid file extension.', ['%source' => $path])); | |
} | |
} | |
throw new EmptyFeedException(); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function defaultFeedConfiguration() { | |
return ['source' => '']; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function defaultConfiguration() { | |
return [ | |
'allowed_extensions' => 'csv xml json', | |
'allowed_schemes' => ['public'], | |
'host' => NULL, | |
'port' => '22', | |
'username' => NULL, | |
'password' => NULL, | |
]; | |
} | |
/** | |
* Fetch file from sftp. | |
* @param \Drupal\feeds\FeedInterface $feed | |
* @param \Drupal\feeds\StateInterface $state | |
* | |
* @return string|null | |
*/ | |
public function getFileFromSftp(FeedInterface $feed, StateInterface $state) { | |
// Source. | |
$path = $feed->getSource(); | |
// Replace token | |
$path = $this->token->replace($path); | |
// Separate file name. | |
$file_name = pathinfo($path, PATHINFO_BASENAME); | |
$server_path = pathinfo($path, PATHINFO_DIRNAME); | |
// Check compatibility and Prepare download directory | |
$downloadDir = 'public://sftp_sync'; | |
if (!$this->fileSystem->prepareDirectory($downloadDir, FileSystemInterface::CREATE_DIRECTORY) | |
) { | |
$this->logger->notice('Download directory is not ready'); | |
return NULL; | |
} | |
// Connecting to sftp. | |
$this->sftp = new SFTP( | |
$this->configuration['host'], | |
$this->configuration['port'] | |
); | |
// Connect to sftp | |
if (!$this->sftp->login($this->configuration['username'], $this->configuration['password'])) { | |
$this->logger->notice('SFTP login failed'); | |
return NULL; | |
} | |
// Change dir | |
$this->sftp->chdir($server_path); | |
try { | |
// Get data from sftp | |
$data = $this->sftp->get(pathinfo($path, PATHINFO_BASENAME)); | |
// Destination file path. | |
$_file = $downloadDir . '/' . $file_name; | |
// Save data to drupal file system | |
$this->fileSystem->saveData( | |
$data, | |
$_file, | |
FileSystemInterface::EXISTS_REPLACE | |
); | |
// Return file path. | |
return $_file; | |
} | |
catch (\Exception $e) { | |
$this->logger->notice($e->getMessage()); | |
} | |
return NULL; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Drupal\feeds_sftp_fetcher\Feeds\Fetcher\Form; | |
use Drupal\Core\Form\FormStateInterface; | |
use Drupal\feeds\FeedInterface; | |
use Drupal\feeds\Plugin\Type\ExternalPluginFormBase; | |
use Drupal\feeds\Utility\File; | |
/** | |
* Provides a form on the feed edit page for the SftpFetcher. | |
*/ | |
class SftpFetcherFeedForm extends ExternalPluginFormBase { | |
/** | |
* {@inheritdoc} | |
*/ | |
public function buildConfigurationForm(array $form, FormStateInterface $form_state, FeedInterface $feed = NULL): array { | |
$args = ['%schemes' => implode(', ', $this->plugin->getConfiguration('allowed_schemes'))]; | |
$form['source'] = [ | |
'#title' => $this->t('Remote server file path'), | |
'#type' => 'textfield', | |
'#default_value' => $feed->getSource(), | |
'#allowed_schemes' => $this->plugin->getConfiguration('allowed_schemes'), | |
'#description' => $this->t('The allowed schemes are: %schemes, You can also use token here.', $args), | |
]; | |
return $form; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function validateConfigurationForm(array &$form, FormStateInterface $form_state, FeedInterface $feed = NULL) { | |
$source = $form_state->getValue('source'); | |
$allowed = $this->plugin->getConfiguration('allowed_extensions'); | |
// Validate a single file. | |
if (!File::validateExtension($source, $allowed)) { | |
$form_state->setError($form['source'], $this->t('%source has an invalid file extension.', ['%source' => $source])); | |
} | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function submitConfigurationForm(array &$form, FormStateInterface $form_state, FeedInterface $feed = NULL) { | |
$feed->setSource($form_state->getValue('source')); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Drupal\feeds_sftp_fetcher\Feeds\Fetcher\Form; | |
use Drupal\Component\Utility\Html; | |
use Drupal\Core\DependencyInjection\ContainerInjectionInterface; | |
use Drupal\Core\Form\FormStateInterface; | |
use Drupal\Core\StreamWrapper\StreamWrapperInterface; | |
use Drupal\Core\StreamWrapper\StreamWrapperManager; | |
use Drupal\feeds\Plugin\Type\ExternalPluginFormBase; | |
use Symfony\Component\DependencyInjection\ContainerInterface; | |
/** | |
* Provides a setting form for the SftpFetcher. | |
*/ | |
class SftpFetcherForm extends ExternalPluginFormBase implements ContainerInjectionInterface { | |
/** | |
* The stream wrapper manager. | |
* | |
* @var \Drupal\Core\StreamWrapper\StreamWrapperManager | |
*/ | |
protected $streamWrapperManager; | |
/** | |
* Constructs a DirectoryFetcherForm object. | |
* | |
* @param \Drupal\Core\StreamWrapper\StreamWrapperManager $streamWrapperManager | |
* The stream wrapper manager. | |
*/ | |
public function __construct(StreamWrapperManager $streamWrapperManager) { | |
$this->streamWrapperManager = $streamWrapperManager; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public static function create(ContainerInterface $container) { | |
return new static($container->get('stream_wrapper_manager')); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function buildConfigurationForm(array $form, FormStateInterface $form_state) { | |
$form['allowed_extensions'] = [ | |
'#type' => 'textfield', | |
'#title' => $this->t('Allowed file extensions'), | |
'#description' => $this->t('Allowed file extensions for upload.'), | |
'#default_value' => $this->plugin->getConfiguration('allowed_extensions'), | |
]; | |
$form['allowed_schemes'] = [ | |
'#type' => 'checkboxes', | |
'#title' => $this->t('Allowed schemes'), | |
'#default_value' => $this->plugin->getConfiguration('allowed_schemes'), | |
'#options' => $this->getSchemeOptions(), | |
'#description' => $this->t('Select the schemes you want to allow for upload.'), | |
]; | |
$form['host'] = [ | |
'#type' => 'textfield', | |
'#title' => $this->t('FTP/SFTP Host'), | |
'#default_value' => $this->plugin->getConfiguration('host'), | |
'#required' => TRUE, | |
'#description' => $this->t("FTP/SFTP host ip or string."), | |
]; | |
$form['port'] = [ | |
'#type' => 'number', | |
'#title' => $this->t('FTP/SFTP Port'), | |
'#default_value' => $this->plugin->getConfiguration('port'), | |
'#required' => TRUE, | |
'#description' => $this->t("Numeric port of remote server."), | |
]; | |
$form['username'] = [ | |
'#type' => 'textfield', | |
'#title' => $this->t('FTP/SFTP Username'), | |
'#default_value' => $this->plugin->getConfiguration('username'), | |
'#required' => TRUE, | |
'#description' => $this->t("FTP/SFTP login user name."), | |
]; | |
$form['password'] = [ | |
'#type' => 'textfield', | |
'#title' => $this->t('FTP/SFTP Password'), | |
'#default_value' => 'CHANGE PASSWORD', | |
'#required' => TRUE, | |
'#description' => $this->t("FTP/SFTP login password. It will not be shown here."), | |
]; | |
return $form; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) { | |
$form_state->setValue('allowed_schemes', array_filter($form_state->getValue('allowed_schemes', []))); | |
$extensions = preg_replace('/\s+/', ' ', trim($form_state->getValue('allowed_extensions', ''))); | |
$form_state->setValue('allowed_extensions', $extensions); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { | |
// Keep password same. | |
$password = $form_state->getValue('password'); | |
if (empty($password) || $password == 'CHANGE PASSWORD') { | |
$form_state->setValue('password', $this->plugin->getConfiguration('password')); | |
} | |
} | |
/** | |
* Returns available scheme options for use in checkboxes or select list. | |
* | |
* @return array | |
* The available scheme array keyed scheme => description. | |
*/ | |
protected function getSchemeOptions() { | |
$options = []; | |
foreach ($this->streamWrapperManager->getDescriptions(StreamWrapperInterface::WRITE_VISIBLE) as $scheme => $description) { | |
$options[$scheme] = Html::escape($scheme . ': ' . $description); | |
} | |
return $options; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment