<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
use Parsedown;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20180906151556 extends AbstractMigration
{
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->abortIf('mysql' !== $this->connection->getDatabasePlatform()->getName(), 'Migration can only be executed safely on \'mysql\'.');
$stmt = $this->connection->prepare('SELECT * FROM config_pdf_field');
$stmt->execute();
while ($row = $stmt->fetch(\PDO::FETCH_OBJ)) {
if (empty($row->mapping)) {
continue;
}
$mapping = unserialize($row->mapping);
foreach ($mapping as $key => $value) {
if (\in_array($value, $this->getMergeFields())) {
$mapping[$key] = array_search($value, $this->getMergeFields());
}
}
$this->addSql('UPDATE config_pdf_field SET mapping = :mapping WHERE id = :id', [
'id' => $row->id,
'mapping' => serialize($mapping),
]);
}
$this->parseString('config_document', ['body', 'header', 'footer'], 'toHtml');
$this->parseString('config_stage', ['message_body'], 'toHtml');
$this->parseString('config_stage_item', ['message_body'], 'toHtml');
$this->parseString('customer_letter', ['body'], 'toHtml');
$this->parseString('customer_message', ['body'], 'toHtml');
$this->parseString('feed_comment', ['body'], 'toHtml');
$this->parseString('issue_comment', ['body'], 'toHtml');
$this->parseString('user', ['signature'], 'toHtml');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->abortIf('mysql' !== $this->connection->getDatabasePlatform()->getName(), 'Migration can only be executed safely on \'mysql\'.');
$stmt = $this->connection->prepare('SELECT * FROM config_pdf_field');
$stmt->execute();
while ($row = $stmt->fetch(\PDO::FETCH_OBJ)) {
if (empty($row->mapping)) {
continue;
}
$mapping = unserialize($row->mapping);
foreach ($mapping as $key => $value) {
if (\array_key_exists($value, $this->getMergeFields())) {
$mapping[$key] = $this->getMergeFields()[$value];
}
}
$this->addSql('UPDATE config_pdf_field SET mapping = :mapping WHERE id = :id', [
'id' => $row->id,
'mapping' => serialize($mapping),
]);
}
$this->parseString('config_document', ['body', 'header', 'footer'], 'toMarkdown');
$this->parseString('config_stage', ['message_body'], 'toMarkdown');
$this->parseString('config_stage_item', ['message_body'], 'toMarkdown');
$this->parseString('customer_letter', ['body'], 'toMarkdown');
$this->parseString('customer_message', ['body'], 'toMarkdown');
$this->parseString('feed_comment', ['body'], 'toMarkdown');
$this->parseString('issue_comment', ['body'], 'toMarkdown');
$this->parseString('user', ['signature'], 'toMarkdown');
}
/**
* @param string $table
* @param string $fields
* @param array $method
*/
private function parseString(string $table, array $fields, string $method)
{
$stmt = $this->connection->prepare(sprintf('SELECT count(1) FROM %s', $table));
$stmt->execute();
// get total entries
$total = $stmt->fetchColumn();
// insert using pagination
for ($i = 0; $i < ceil($total / 100); ++$i) {
$stmt = $this->connection->prepare(sprintf('SELECT * FROM %s ORDER BY id ASC LIMIT %d, 100', $table, 100 * $i));
$stmt->execute();
while ($row = $stmt->fetch(\PDO::FETCH_OBJ)) {
$sets = [];
$params = [];
foreach ($fields as $field) {
if (!empty($row->$field)) {
$sets[] = sprintf('%s = :%s', $field, $field);
$params[$field] = $this->$method($row->$field);
}
}
if (\count($params)) {
$this->addSql(sprintf('UPDATE %s SET %s WHERE id = :id', $table, implode(', ', $sets)), array_merge([
'id' => $row->id,
], $params));
}
}
}
}
/**
* @param string $markdown
*
* @return string
*/
private function toHtml(string $markdown): string
{
$converter = new Parsedown();
$html = $converter->text($markdown);
$html = preg_replace(
'/\[\[embed_field key=("|")(\w+)("|") \/(\])?(\])?/isU',
'<span class="text-editor-merge-field-container"><span class="text-editor-merge-field is-recipient" data-name="$2" contenteditable="false"># $2</span></span>',
$html
);
$html = preg_replace(
'/\[\[signature_field id=("|")(\w+)("|") placeholder=("|")([\w\s]+)("|") \/(\])?(\])?/isU',
'<div class="signature-pad-link" data-id="$2" data-placeholder="$5" contenteditable="false">$5</div>',
$html
);
$html = preg_replace(
'/\[\[signature_field id=("|")(\w+)("|") placeholder=("|")([\w\s]+)("|") img=("|")([\w_\:\.\-\=\/]+)("|") \/(\])?(\])?/isU',
'<div class="signature-pad-link" data-id="$2" data-placeholder="$5" data-image="$8"><img src="$8" /></div>',
$html
);
foreach ($this->getMergeFields() as $to => $from) {
$html = str_replace(sprintf('data-name="%s"', $from), sprintf('data-name="%s"', $to), $html);
$html = str_replace(sprintf('contenteditable="false"># %s</span>', $from), sprintf('contenteditable="false"># %s</span>', $to), $html);
$html = str_replace(sprintf('{{%s}}', $from), sprintf('<span class="text-editor-merge-field-container"><span class="text-editor-merge-field is-recipient" data-name="%s" contenteditable="false"># %s</span></span>', $to, $to), $html);
}
return $html;
}
/**
* @param string $html
*
* @return string
*/
private function toMarkdown(string $html): string
{
$markdown = preg_replace(
'/<span class="text-editor-merge-field-container"><span class="text-editor-merge-field is-recipient"(.*)data-name="(\w+)"(.*)># (\w+)<\/span><\/span>/isU',
'[[embed_field key="$1" /]]',
$html
);
$markdown = preg_replace(
'/<div class="signature-pad-link"(.*)data-id="(\w+)" data-placeholder="([\w\s]+)"(.*)>([\w\s]+)<\/div>/isU',
'[[signature_field id="$2" placeholder="$3" /]]',
$markdown
);
$markdown = preg_replace(
'/<div class="signature-pad-link"(.*)data-id="(\w+)" data-placeholder="([\w\s]+)" data-image="([\w_\:\.\-\=\/]+)"(.*)>(.+)<\/div>/isU',
'[[signature_field id="$2" placeholder="$3" img="$4" /]]',
$markdown
);
foreach ($this->getMergeFields() as $to => $from) {
$markdown = str_replace(sprintf('[[embed_field key="%s"', $to), sprintf('[[embed_field key="%s"', $from), $markdown);
$markdown = str_replace(sprintf('[[signature_field id="%s"', $to), sprintf('[[signature_field id="%s"', $from), $markdown);
}
// get rid of attributes!
$elements = ['p', 'span', 'ul', 'ol', 'li', 'strong', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
foreach ($elements as $element) {
$markdown = preg_replace("/<$element.*?>/", "<$element>", $markdown);
}
$regexMap = [
'p' => '',
'\/p' => "\n",
'span' => '',
'span.*?' => '',
'\/span' => '',
'h1' => '#',
'h2' => '##',
'h3' => '###',
'h4' => '####',
'h5' => '#####',
'h6' => '######',
'\/h\d' => "\n",
'br' => "\n",
'br\s\/' => "\n",
'strong' => '__',
'\/strong' => '__',
'em' => '_',
'\/em' => '_',
];
// replace simple tags w/ markdown equivalent
foreach ($regexMap as $element => $replacement) {
$markdown = preg_replace("/<$element>/", $replacement, $markdown);
}
// images: Capture <img> tags, isolate src
if (preg_match_all('/<img.*src="([^\s"]*?)".*>?/', $markdown, $matches)) {
// swap markdown replacement for <img> markup for each match
foreach ($matches[0] as $i => $img_markup) {
$url = $matches[1][$i];
// alt tags
$alt = null;
if (preg_match('/alt="([^\s"]*?)"/', $img_markup, $alt_match)) {
$alt = $alt[1];
}
// build markdown and swap
$img_markdown = "";
$markdown = str_replace($img_markup, $img_markdown, $markdown);
}
}
// links: Capture <a> tags, isolate href
if (preg_match_all('/<a.*?href="([^\s"]*?)".*?>(.*?)?<\/a>/', $markdown, $matches)) {
// Swap markdown replacement for <a> markup for each match
foreach ($matches[0] as $i => $a_markup) {
$href = $matches[1][$i];
$text = $matches[2][$i];
// Build markdown and swap
$a_markdown = "[$text]($href)";
$markdown = str_replace($a_markup, $a_markdown, $markdown);
}
}
// unordered lists
if (preg_match_all('/<ul>(.*?)<\/ul>/s', $markdown, $matches)) {
$markdown = preg_replace('/<ul>|<\/ul>/', '', $markdown);
foreach ($matches[0] as $ul) {
if (preg_match_all('/<li>(.*?)<\/li>/s', $ul, $list_items)) {
foreach ($list_items[0] as $i => $li_markup) {
$li_inner = $list_items[1][$i];
$li_markdown = '- '.$li_inner;
$markdown = str_replace($li_markup, $li_markdown, $markdown);
}
}
}
}
// ordered lists
if (preg_match_all('/<ol>(.*?)<\/ol>/s', $markdown, $matches)) {
$markdown = preg_replace('/<ol>|<\/ol>/', '', $markdown);
foreach ($matches[0] as $ol) {
if (preg_match_all('/<li>(.*?)<\/li>/s', $ol, $list_items)) {
foreach ($list_items[0] as $i => $li_markup) {
$li_inner = $list_items[1][$i];
$li_markdown = $i + 1 .'. '.$li_inner;
$markdown = str_replace($li_markup, $li_markdown, $markdown);
}
}
}
}
// blockquotes
if (preg_match_all('/<blockquote>(.*?)<\/blockquote>/s', $markdown, $matches)) {
foreach ($matches[1] as $i => $inner_html) {
$blockquote_markup = $matches[$i];
$blockquote_markdown = '';
$lines = explode("\n", $inner_html);
foreach ($lines as $line) {
$blockquote_markdown .= '> '.$line."\n";
}
$markdown = str_replace($blockquote_markup, $blockquote_markdown, $markdown);
}
}
return $markdown;
}
/**
* @return array
*/
private function getMergeFields(): array
{
static $fields = [];
if (\count($fields)) {
return $fields;
}
$stmt = $this->connection->prepare('SELECT * FROM config_address');
$stmt->execute();
while ($row = $stmt->fetch(\PDO::FETCH_OBJ)) {
$fields = array_merge($fields, [
sprintf('address_%d_phone_number', $row->id) => sprintf('address_%d_telephone', $row->id),
sprintf('address_%d_fax_number', $row->id) => sprintf('address_%d_fax', $row->id),
sprintf('address_%d_use_address', $row->id) => sprintf('address_%d_flag_address', $row->id),
sprintf('address_%d_use_phone_number', $row->id) => sprintf('address_%d_flag_telephone', $row->id),
sprintf('address_%d_use_fax_number', $row->id) => sprintf('address_%d_flag_fax', $row->id),
sprintf('address_%d_street', $row->id) => sprintf('address_%d_street_address', $row->id),
sprintf('address_%d_zip', $row->id) => sprintf('address_%d_postcode', $row->id),
]);
}
$fields = array_merge($fields, [
'customer_id' => 'id',
'customer_first_name' => 'customer_firstname',
'customer_middle_name' => 'customer_middle_initial',
'customer_last_name' => 'customer_lastname',
'customer_birthday' => 'customer_birthday',
'customer_marital_status' => 'customer_marital_status',
'customer_spouse_first_name' => 'customer_spouses_firstname',
'customer_spouse_middle_name' => 'customer_spouses_middle_initial',
'customer_spouse_last_name' => 'customer_spouses_lastname',
'customer_spouse_birthday' => 'customer_spouses_birthday',
'customer_company_name' => 'customer_company',
'customer_company_street' => 'company_street_address',
'customer_company_city' => 'company_city',
'customer_company_state' => 'company_state',
'customer_company_zip' => 'company_postcode',
'customer_billing_company_name' => 'billing_company',
'customer_billing_first_name' => 'billing_firstname',
'customer_billing_last_name' => 'billing_lastname',
'customer_billing_street' => 'billing_street_address',
'customer_billing_city' => 'billing_city',
'customer_billing_state' => 'billing_state',
'customer_billing_zip' => 'billing_postcode',
'customer_billing_as_address' => 'same_as_address',
'customer_phone_number' => 'customer_telephone',
'customer_spouse_phone_number' => 'customer_spouses_telephone',
'customer_fax_number' => 'customer_fax',
'customer_mobile_number' => 'customer_mobile',
'customer_work_number' => 'customer_work_number',
'customer_ssn' => 'customer_ssn',
'customer_spouse_ssn' => 'customer_spouses_ssn',
'customer_ein' => 'customer_ein',
'customer_email' => 'customer_email_address',
'customer_spouse_email' => 'customer_spouses_email_address',
'customer_password' => 'customer_password',
'customer_plain_password' => 'customer_raw_password',
'customer_irs_debt' => 'irs_debt',
'customer_state_debt' => 'state_debt',
'customer_checking_saving' => 'checking_saving',
'customer_available_credit' => 'available_credit',
'customer_credit_owed' => 'credit_owed',
'customer_fee' => 'fee',
'customer_years_filed' => 'years',
'customer_biz_years_filed' => 'biz_years',
'customer_pqa_received_at' => 'pqa_received_date',
'customer_bqa_received_at' => 'bqa_received_date',
'customer_rating' => 'rating',
'customer_interview_time' => 'interview_time',
'customer_stage_started_at' => 'stage_started',
'customer_stage_percent_done' => 'done_percent',
'customer_converted_at' => 'date_converted',
'customer_last_login' => 'last_login',
'customer_created_at' => 'date_added',
'customer_modified_at' => 'last_modified',
'customer_street' => 'customer_street_address',
'customer_city' => 'customer_city',
'customer_state' => 'customer_state',
'customer_zip' => 'customer_postcode',
'customer_user' => 'administrators_id',
'customer_company' => 'customers_companies_id',
'customer_source' => 'source_id',
'customer_level' => 'level',
'customer_case_manager_user' => 'cm_user',
'customer_lead_agent_user' => 'la_user',
'customer_financial_user' => 'financial_user',
'customer_service_user' => 'service_sales_user',
'customer_processor_user' => 'processor_user',
'customer_resolution_specialist_user' => 'resolution_specialist_user',
'customer_stage' => 'stage_id',
'customer_status' => 'status_id',
]);
$fields = array_merge($fields, [
'interview_filed_last3_years' => 'interview_filed_last_3_years',
'interview_home_value80' => 'interview_home_value_80',
'interview_car_payment1' => 'interview_car_payment_1',
'interview_car_payment2' => 'interview_car_payment_2',
'interview_taxes1530' => 'interview_taxes_15_30',
'interview_total_equity2' => 'interview_total_equity_2',
]);
$fields = array_merge($fields, [
'card_brand' => 'cc_type',
'card_owner' => 'cc_owner',
'card_number' => 'cc_number',
'card_exp_month' => 'cc_expires_month',
'card_exp_year' => 'cc_expires_year',
'card_expires' => 'cc_expires',
'card_cvc' => 'cc_cvc',
'card_scheduling' => 'cc_scheduling',
'e_check_owner' => 'echk_owner',
'e_check_bank_name' => 'echk_bank',
'e_check_account_number' => 'echk_account',
'e_check_routing' => 'echk_routing',
'e_check_number' => 'echk_number_check',
'e_check_phone_number' => 'echk_telephone',
'e_check_scheduling' => 'echk_scheduling',
]);
return $fields;
}
}