In Perl Tkx I created my own popups which work great.
But I would like to embed those built-in icons, like info, question.
Does anyone know how I can do that on my own widgets and how?
sub PopDialog {
my ($TITLE, $NOTE, #buttons) = #_;
my (#butt, $ret);
my $wait = 1;
my $xwm = Tkx::widget->new(".");
my $popwm = $xwm->new_toplevel();
$popwm->g_wm_title("$TITLE");
$popwm->g_wm_minsize(200, 10);
$popwm->g_wm_resizable(0, 0);
my $back = $popwm->new_ttk__frame(-padding => "5 5 5 5");
$back->g_grid(-column => 0, -row => 0, -sticky => "n");
$popwm->g_grid_columnconfigure(0, -weight => 1);
$popwm->g_grid_rowconfigure(0, -weight => 1);
if ($NOTE !~ /^$/) {
my $frm0 = $back->new_ttk__frame(-padding => 5);
my $label = $frm0->new_ttk__label(-text => "$NOTE", -font => 'logo_font')->
g_grid(-column => 0, -row => 0);
$frm0->g_pack();
}
my $frm1 = $back->new_ttk__frame(-padding => 5);
for my $x (0 .. $#buttons) {
$butt[$x] = $frm1->new_ttk__button(
-text => "$buttons[$x]",
-underline => 0,
-command => sub { $ret = "$buttons[$x]"; $wait = 0; }
)->g_grid(-column => $x, -row => 0);
}
$frm1->g_pack();
$popwm->g_wm_protocol(WM_DELETE_WINDOW => sub { $ret = "Exit"; $wait = 0; }); # Close Button returns "Exit"
$popwm->g_bind('<Unmap>', sub { $popwm->g_wm_deiconify; $xwm->g_focus; }); # No minimizing to Icon Allowed
while ($wait) {
Tkx::update();
$popwm->g_focus;
}
$popwm->g_destroy;
return $ret;
}
Related
I copy order_conf.tpl and order_conf.txt file from mail folder and rename it. Now add override to classes/order/OrderHistory.php
I change function sendemail() to:
public function sendEmail($order, $template_vars = false)
{
$result = Db::getInstance()->getRow('
SELECT osl.`template`, c.`lastname`, c.`firstname`, osl.`name` AS osname, c.`email`, os.`module_name`, os.`id_order_state`, os.`pdf_invoice`, os.`pdf_delivery`
FROM `'._DB_PREFIX_.'order_history` oh
LEFT JOIN `'._DB_PREFIX_.'orders` o ON oh.`id_order` = o.`id_order`
LEFT JOIN `'._DB_PREFIX_.'customer` c ON o.`id_customer` = c.`id_customer`
LEFT JOIN `'._DB_PREFIX_.'order_state` os ON oh.`id_order_state` = os.`id_order_state`
LEFT JOIN `'._DB_PREFIX_.'order_state_lang` osl ON (os.`id_order_state` = osl.`id_order_state` AND osl.`id_lang` = o.`id_lang`)
WHERE oh.`id_order_history` = '.(int)$this->id.' AND os.`send_email` = 1');
if (isset($result['template']) && Validate::isEmail($result['email'])) {
ShopUrl::cacheMainDomainForShop($order->id_shop);
$topic = $result['osname'];
/*----------------------
-START OF INSERTED CODE-
----------------------*/
/* GET THE PRODUCTS */
$order_details = $order->getProducts();
$product_var_tpl_list = array();
foreach ($order_details as $id => &$order_detail) {
$product_var_tpl = array(
'reference' => $order_detail['product_reference'],
'name' => $order_detail['product_name'].(isset($order_detail['product_attributes']) ? ' - '.$order_detail['product_attributes'] : ''),
'unit_price' => Tools::displayPrice($order_detail['unit_price_tax_incl'], $this->context->currency, false),
'price' => Tools::displayPrice($order_detail['total_price_tax_incl'], $this->context->currency, false),
'quantity' => $order_detail['product_quantity'],
'customization' => $order_detail['customizedDatas']
);
$product_var_tpl_list[] = $product_var_tpl;
} // end foreach ($order_detail)
$product_list_txt = '';
$product_list_html = '';
if (count($product_var_tpl_list) > 0) {
$product_list_txt = $this->getEmailTemplateContent('order_conf_product_list.txt', Mail::TYPE_TEXT, $product_var_tpl_list);
$product_list_html = $this->getEmailTemplateContent('order_conf_product_list.tpl', Mail::TYPE_HTML, $product_var_tpl_list);
}
/* GET THE DISCOUNTS */
$cart_rules = $order->getCartRules();
foreach ($cart_rules as $id => &$cart_rule) {
$cart_rules_list[] = array(
'voucher_name' => $cart_rule['name'],
'voucher_reduction' => ($cart_rule['value'] != 0.00 ? '-' : '').Tools::displayPrice($cart_rule['value'], $this->context->currency, false)
);
}
$cart_rules_list_txt = '';
$cart_rules_list_html = '';
if (count($cart_rules_list) > 0) {
$cart_rules_list_txt = $this->getEmailTemplateContent('order_conf_cart_rules.txt', Mail::TYPE_TEXT, $cart_rules_list);
$cart_rules_list_html = $this->getEmailTemplateContent('order_conf_cart_rules.tpl', Mail::TYPE_HTML, $cart_rules_list);
}
/* GET ORDER DETAILS, delivery, invoice, amount... etc */
$invoice_address = new Address((int)$order->id_address_invoice);
$invoiceAddressPatternRules = Tools::jsonDecode(Configuration::get('PS_INVCE_INVOICE_ADDR_RULES'), true);
$deliveryAddressPatternRules = Tools::jsonDecode(Configuration::get('PS_INVCE_DELIVERY_ADDR_RULES'), true);
$country = new Country((int)$invoice_address->id_country);
$delivery_address = null;
$formatted_delivery_address = '';
if (isset($order->id_address_delivery) && $order->id_address_delivery) {
$delivery_address = new Address((int)$order->id_address_delivery);
}
$carrier = new Carrier((int)($order->id_carrier), $order->id_lang);
/* ATTACH INFORMATION TO SMARTY VARIABLE*/
$data = array(
'{lastname}' => $result['lastname'],
'{firstname}' => $result['firstname'],
'{id_order}' => (int)$this->id_order,
'{delivery_block_txt}' => AddressFormat::generateAddress($delivery_address, $deliveryAddressPatternRules, ', ', ' '),
'{invoice_block_txt}' => AddressFormat::generateAddress($invoice_address, $invoiceAddressPatternRules, ', ', ' '),
'{delivery_block_html}' => AddressFormat::generateAddress($delivery_address, $deliveryAddressPatternRules, '<br />',' ', array(
'firstname' => '<span style="font-weight:bold;">%s</span>',
'lastname' => '<span style="font-weight:bold;">%s</span>'
)),
'{invoice_block_html}' => AddressFormat::generateAddress($invoice_address, $invoiceAddressPatternRules, '<br />',' ', array(
'firstname' => '<span style="font-weight:bold;">%s</span>',
'lastname' => '<span style="font-weight:bold;">%s</span>'
)),
'{delivery_company}' => $delivery_address->company,
'{delivery_firstname}' => $delivery_address->firstname,
'{delivery_lastname}' => $delivery_address->lastname,
'{delivery_address1}' => $delivery_address->address1,
'{delivery_address2}' => $delivery_address->address2,
'{delivery_city}' => $delivery_address->city,
'{delivery_postal_code}' => $delivery_address->postcode,
'{delivery_country}' => $delivery_address->country,
'{delivery_state}' => $delivery_address->id_state ? $delivery_state->name : '',
'{delivery_phone}' => ($delivery_address->phone) ? $delivery_address->phone : $delivery_address->phone_mobile,
'{delivery_other}' => $delivery_address->other,
'{invoice_company}' => $invoice_address->company,
'{invoice_vat_number}' => $invoice_address->vat_number,
'{invoice_firstname}' => $invoice_address->firstname,
'{invoice_lastname}' => $invoice_address->lastname,
'{invoice_address2}' => $invoice_address->address2,
'{invoice_address1}' => $invoice_address->address1,
'{invoice_city}' => $invoice_address->city,
'{invoice_postal_code}' => $invoice_address->postcode,
'{invoice_country}' => $invoice_address->country,
'{invoice_state}' => $invoice_address->id_state ? $invoice_state->name : '',
'{invoice_phone}' => ($invoice_address->phone) ? $invoice_address->phone : $invoice_address->phone_mobile,
'{invoice_other}' => $invoice_address->other,
'{order_name}' => $order->getUniqReference(),
'{date}' => Tools::displayDate(date('Y-m-d H:i:s'), null, 1),
'{carrier}' => (!isset($carrier->name)) ? Tools::displayError('No carrier') : $carrier->name,
'{payment}' => Tools::substr($order->payment, 0, 32),
'{products}' => $product_list_html,
'{products_txt}' => $product_list_txt,
'{discounts}' => $cart_rules_list_html,
'{discounts_txt}' => $cart_rules_list_txt,
'{total_paid}' => Tools::displayPrice($order->total_paid, $this->context->currency, false),
'{total_products}' => Tools::displayPrice(Product::getTaxCalculationMethod() == PS_TAX_EXC ? $order->total_products : $order->total_products_wt, $this->context->currency, false),
'{total_discounts}' => Tools::displayPrice($order->total_discounts, $this->context->currency, false),
'{total_shipping}' => Tools::displayPrice($order->total_shipping, $this->context->currency, false),
'{total_wrapping}' => Tools::displayPrice($order->total_wrapping, $this->context->currency, false),
'{total_tax_paid}' => Tools::displayPrice(($order->total_products_wt - $order->total_products) + ($order->total_shipping_tax_incl - $order->total_shipping_tax_excl), $this->context->currency, false)
);
/*---------------------
!-END OF INSERTED CODE-
---------------------*/
if ($result['module_name']) {
$module = Module::getInstanceByName($result['module_name']);
if (Validate::isLoadedObject($module) && isset($module->extra_mail_vars) && is_array($module->extra_mail_vars)) {
$data = array_merge($data, $module->extra_mail_vars);
}
}
if ($template_vars) {
$data = array_merge($data, $template_vars);
}
$data['{total_paid}'] = Tools::displayPrice((float)$order->total_paid, new Currency((int)$order->id_currency), false);
if (Validate::isLoadedObject($order)) {
// Attach invoice and / or delivery-slip if they exists and status is set to attach them
if (($result['pdf_invoice'] || $result['pdf_delivery'])) {
$context = Context::getContext();
$invoice = $order->getInvoicesCollection();
$file_attachement = array();
if ($result['pdf_invoice'] && (int)Configuration::get('PS_INVOICE') && $order->invoice_number) {
Hook::exec('actionPDFInvoiceRender', array('order_invoice_list' => $invoice));
$pdf = new PDF($invoice, PDF::TEMPLATE_INVOICE, $context->smarty);
$file_attachement['invoice']['content'] = $pdf->render(false);
$file_attachement['invoice']['name'] = Configuration::get('PS_INVOICE_PREFIX', (int)$order->id_lang, null, $order->id_shop).sprintf('%06d', $order->invoice_number).'.pdf';
$file_attachement['invoice']['mime'] = 'application/pdf';
}
if ($result['pdf_delivery'] && $order->delivery_number) {
$pdf = new PDF($invoice, PDF::TEMPLATE_DELIVERY_SLIP, $context->smarty);
$file_attachement['delivery']['content'] = $pdf->render(false);
$file_attachement['delivery']['name'] = Configuration::get('PS_DELIVERY_PREFIX', Context::getContext()->language->id, null, $order->id_shop).sprintf('%06d', $order->delivery_number).'.pdf';
$file_attachement['delivery']['mime'] = 'application/pdf';
}
} else {
$file_attachement = null;
}
if (!Mail::Send((int)$order->id_lang, $result['template'], $topic, $data, $result['email'], $result['firstname'].' '.$result['lastname'],
null, null, $file_attachement, null, _PS_MAIL_DIR_, false, (int)$order->id_shop)) {
return false;
}
}
ShopUrl::resetMainDomainCache();
}
return true;
}
protected function getEmailTemplateContent($template_name, $mail_type, $var)
{
$email_configuration = Configuration::get('PS_MAIL_TYPE');
if ($email_configuration != $mail_type && $email_configuration != Mail::TYPE_BOTH) {
}
$theme_template_path = _PS_THEME_DIR_.'mails'.DIRECTORY_SEPARATOR.Context::getContext()->language->iso_code.DIRECTORY_SEPARATOR.$template_name;
$default_mail_template_path = _PS_MAIL_DIR_.Context::getContext()->language->iso_code.DIRECTORY_SEPARATOR.$template_name;
if (Tools::file_exists_cache($theme_template_path)) {
$default_mail_template_path = $theme_template_path;
}
if (Tools::file_exists_cache($default_mail_template_path)) {
Context::getContext()->smarty->assign('list', $var);
return Context::getContext()->smarty->fetch($default_mail_template_path);
}
return ' ';
}
In status I create new one status and add option to send my new email to customer, when in order I change status email is send to customer with data but there is missing all product detail from orders.
I don't know how I can correct get this product in my override file.
You don't have the needed templates in your context backoffice language.
Copy files:
/mails/en/order_conf_cart_rules.tpl
/mails/en/order_conf_cart_rules.txt
/mails/en/order_conf_product_list.tpl
/mails/en/order_conf_product_list.txt
To:
/mails/YOUR_BACKOFFICE_USER_LANG_ISO_CODE/order_conf_cart_rules.tpl
/mails/YOUR_BACKOFFICE_USER_LANG_ISO_CODE/order_conf_cart_rules.txt
/mails/YOUR_BACKOFFICE_USER_LANG_ISO_CODE/order_conf_product_list.tpl
/mails/YOUR_BACKOFFICE_USER_LANG_ISO_CODE/order_conf_product_list.txt
validate(
#_,
{
foo => {
callbacks => {
'smaller than a breadbox' => sub { shift() < $breadbox },
'green or blue' => sub {
return 1 if $_[0] eq 'green' || $_[0] eq 'blue';
&$failed(‘**fieldname** value is Invalid’);
}
bar => {
callbacks => {
'yellow or red' => sub {
return 1 if $_[0] eq 'yellow ' || $_[0] eq 'red';
&$failed(‘**fieldname** value is Invalid’);
}
}
}
}
);
Params::Validate - In the above code if my validation fails, I am calling the subroutine failed in which I am displaying the error message. I want to get field name from callbacks in params validate for which the validation has failed instead of directly passing the field name in the failed subroutine. Here foo and bar are fieldnames. How can I get the field name?
You could try something like this:
use strict;
use warnings;
use Params::Validate;
my %template =
(
bar => {
'color correct' => sub {
my ($fieldname, $value) = #_[0..1];
return 1 if $value eq 'green' || $value eq 'blue';
failed("'$fieldname': value '$value' is invalid");
}
},
foo => {
'smaller than a breadbox' => sub {
my ($fieldname, $value) = #_[0..1];
return 1 if $value < 20;
failed("'$fieldname' value '$value' is invalid");
}
}
);
func( bar => 'green', foo => 14 );
func( bar => 'yellow', foo => 17 );
sub func {
my %validate = map { $_ => { callbacks => get_callbacks( $_, $template{$_} ) } }
keys %template;
validate( #_, \%validate );
}
sub get_callbacks {
my ( $fname, $callbacks ) = #_;
my %cb;
for my $name (keys %$callbacks ) {
$cb{$name} = sub {
my $fieldname = $fname;
$callbacks->{$name}->( $fieldname, #_ )
};
}
return \%cb;
}
sub failed {
die $_[0];
}
Note: this uses closures to define a persistent fieldname variable. See perlsub for more information.
Below is my Code with the Hash
#!/usr/bin/perl
use warnings;
use JSON::PP; # Just 'use JSON;' on most systems
my %name = (
'sl' => {
'fsd' => {
'conf' => {
'ul' => '/sl/fsd/conf/ul',
'si' => '/sl/fsd/conf/si',
'ho1' => '/sl/fsd/conf/ho1'
}
}
},
're' => {
'fsd' => {
'cron' => {
'README' => '/re/fsd/cron/README'
},
'bin' => {
'db' => {
'smart.p_add_tag' => '/re/fsd/bin/db/smart.p_add_tag',
'smart.p_tag_partition' => '/re/fsd/bin/db/smart.p_tag_partition',
'smart.p_add_tag_type' => '/re/fsd/bin/db/smart.p_add_tag_type'
}
},
'doc' => {
'SMART' => '/re/fsd/doc/SMART',
'README' => '/re/fsd/doc/README'
},
'data' => {
'README' => '/re/fsd/data/README'
},
'conf' => {
'al1' => '/re/fsd/conf/al1',
'file' => '/re/fsd/conf/file',
'ho' => '/re/fsd/conf/ho',
'al3' => '/re/fsd/conf/al3',
'hst' => '/re/fsd/conf/hst',
'us' => '/re/fsd/conf/us',
'README' => '/re/fsd/conf/README',
'al2' => '/re/fsd/conf/al2'
}
}
}
);
(my $root) = keys %name;
my %nodes = ();
my %tree = ();
my #queue = ($root);
list_children(\%name, \#queue, \%nodes) while #queue;
my $tree = build_tree($root, \%nodes);
my $json = JSON::PP->new->pretty; # prettify for human consumption
print $json->encode($tree);
sub list_children {
my $adjac = shift;
my $queue = shift;
my $nodes = shift;
my $node = shift #$queue;
my #children = keys %{$adjac->{$node}};
#children = grep { ! exists $nodes->{$_}} #children;
$nodes->{$node} = \#children;
push #$queue, #children;
}
sub build_tree {
my $root = shift;
my $nodes = shift;
my #children;
for my $child (#{$nodes->{$root}}) {
push #children, build_tree($child, $nodes);
}
my %h = ('text' => $root,
'children' => \#children);
return \%h;
}
I'm trying to output JSONified hash, but it is only traversing upto two levels. whereas i need it to traverse all upto the last child node of each parent. Can someone please help to achieve this.
Below is current output
{
"text" : "sl",
"children" : [
{
"text" : "fsd",
"children" : []
}
]
}
Normally, transforming the hash, and then json-ing is not the most efficient idea, because you're going to make one traversal to transform the hash and JSON's going to make one to json-ify it, and JSON is a type of transform of a hash.
However, JSON is usually done with XS, which means that the second traversal is faster, at least. That and JSON behavior is standardized.
use 5.016;
use strict;
use warnings;
use Data::Dumper ();
use JSON;
my $hash
= {
'Foods' => {
'fruits' => {
'orange' => '1',
'apple' => '2',
},
'Vegetables' => {
'tomato' => '3',
'carrot' => '1',
'cabbage' => '2',
}
}
};
sub descend {
my ( $structure, $block ) = #_;
my $res;
while ( my ( $k, $v ) = each %$structure ) {
$block->( $structure, $k, $v );
if ( ref( $v ) eq 'HASH' ) {
$res = descend( $v, $block );
}
}
return $res;
}
my $new = {};
my $curr = $new;
descend( $hash => sub {
my ( $lvl, $k, $v ) = #_;
my $node = { text => $k };
$curr->{children} //= [];
push $curr->{children}, $node;
if ( ref( $v ) eq 'HASH' ) {
$curr = $node;
}
else {
$node->{children} = { text => $v };
}
});
# allow for the root-level special case, and retrieve the first child.
$new = $new->{children}[0];
say Data::Dumper->Dump( [ $new ], [ '$new' ] );
say JSON->new->encode( $new );
I have a ZF2 form and validators.
I located at http://example.com/public/questions/edit/5730/2770,
where 5730 - $_GET['variant_id'], 2770 - $_GET['test_id'].
When I set input to empty value and submit form - I have an error, and ZF2 redirect me to http://example.com/public/questions/edit/5730 - without test_id (/2770).
How I can redirect me to a valid url? Thank all for answers.
Action:
public function editAction()
{
$language = 'EN';
$request = $this->getRequest();
$this->layout()->setVariable('messenger', 'Edit Questions');
$id = $this->params()->fromRoute('id');
$variantId = $this->params()->fromRoute('variant_id');
$sm = $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter');
$stCategories = new CategoriesTable($sm);
$conFunc = new FunctionsController();
$form = new Form\AddQuestionsForm();
$stCVariants = new ContestVariantsTable($sm);
$stQuestions = new QuestionsTable($sm);
$categoryList = $stCategories->getCategories($language);
$categories = $conFunc->_getSubs(null, $categoryList);
$config = $this->getServiceLocator()->get('config');
$folder = $config['settings']['url'] . $config['settings']['media_files'];
if (empty($id) && !$request->isPost()) {
$this->redirect()->toRoute('stickynotes', array('controller' => 'stickynotes', 'action' => 'contests'));
} elseif ($request->isPost()) {
$form->setInputFilter($stQuestions->getAddQuestionsFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$arrPost = (array) $request->getPost();
$arrFile = (array) $request->getFiles();
$postData = array_merge_recursive($arrPost, $arrFile);
$tryAddQuestion = $stQuestions->updateQuestions($postData);
if ($tryAddQuestion['query'] && $tryAddQuestion['exception'] === null) {
$isUpload = new \Zend\Validator\File\UploadFile();
if ($isUpload->isValid($postData['filebutton'])) {
$path_parts = pathinfo($postData['filebutton']['name']);
$extension = '.' . $path_parts['extension'];
$filename = $tryAddQuestion['lastId'];
$config = $this->getServiceLocator()->get('config');
$folder = $config['settings']['media_files'];
if ($postData['AddQuestionMedia'] == 'image') {
$validator = new \Zend\Validator\File\IsImage();
$validator2 = new \Zend\Validator\File\Extension(array('png', 'jpeg', 'jpg', 'gif'));
if ($validator->isValid($postData['filebutton'])
&& $validator2->isValid($postData['filebutton'])) {
$filter = new \Zend\Filter\File\Rename($folder . 'images/' . $filename . $extension);
$filter->filter($postData['filebutton']);
chmod($config['settings']['media_files'] . 'images/' . $filename . $extension, 0644);
$stQuestions->updateQuestionsFile($filename, $extension);
}
} elseif ($postData['AddQuestionMedia'] == 'video') {
$validator = new \Zend\Validator\File\Extension(array('mp4'));
if ($validator->isValid($postData['filebutton'])) {
$filter = new \Zend\Filter\File\Rename($folder . 'videos/' . $filename . '.mp4');
$filter->filter($postData['filebutton']);
chmod($config['settings']['media_files'] . 'videos/' . $filename . '.mp4', 0644);
$stQuestions->updateQuestionsFile($filename, $extension);
}
} elseif ($postData['AddQuestionMedia'] == 'audio') {
$validator = new \Zend\Validator\File\Extension(array('mp3'));
if ($validator->isValid($postData['filebutton'])) {
$filter = new \Zend\Filter\File\Rename($folder . 'sounds/' . $filename . '.mp3');
$filter->filter($postData['filebutton']);
chmod($config['settings']['media_files'] . 'sounds/' . $filename . '.mp3', 0644);
$stQuestions->updateQuestionsFile($filename, $extension);
}
} else {
$this->layout()->setVariable('messenger_error', 'Uploaded file have incorrect format');
}
}
$this->layout()->setVariable('messenger_info', 'Question has been updated!');
$this->redirect()->toRoute('questions', array('controller' => 'questions', 'action' => 'edit',
'id' => $id, 'variant_id' => $postData['question_id']));
} elseif(!empty($tryAddContest['exception'])) {
$this->layout()->setVariable('messenger_error', 'Failed with DB while update question. Please try again. ' . $tryAddQuestion['exception']);
} else {
$this->layout()->setVariable('messenger_error', 'Failed while update question. Please try again.');
}
if (!empty($postData['variant_id'])) {
$stCVariants->addEntity($postData['variant_id'], $tryAddQuestion['lastId']);
}
}
} else {
if (!empty($variantId)) {
$getContest = $stCVariants->getSingleContest($variantId);
$progressions = array();
$used_progressions = $stCVariants->getUsedProgressions($id);
for ($i=$getContest['progression_start']; $i<=$getContest['progression_stop']; $i++) {
if (!in_array($i, $used_progressions))
$progressions[] = $i;
}
$form->remove('AddQuestionProgression');
$form->getInputFilter()->remove('AddQuestionProgression');
$select = new \Zend\Form\Element\Select('AddQuestionProgression');
$select->setValueOptions($progressions)->setAttributes(array(
'id' => 'progression_id',
'class' => 'form-control',
'style' => 'width: 408px;',
));
$form->get('variant_id')->setValue($id);
$form->add($select);
}
$getQuestion = $stQuestions->getSingleQuestion($id);
switch ($getQuestion['media_type']) {
case 'image':
$folder .= 'images/' . $getQuestion['media_content'];
break;
case 'video':
$folder .= 'videos/' . $getQuestion['media_content'];
break;
case 'audio':
$folder .= 'sounds/' . $getQuestion['media_content'];
break;
}
$form->get('variant_id')->setValue($id);
$form->get('question_id')->setValue($variantId);
}
return array(
'form' => $form,
'categories' => $categories,
'url' => $folder,
'id' => $id
);
}
Perl's Moose is different from other object systems, so it's not always clear how to translate an example known from other languages into Moose lingo. Consider the following Java example of Rectangle and Square, where a Square instance (a square being a special rectangle) delegates calls to area() to an instance of Rectangle to which it hold a private reference.
package geometry;
class Rectangle {
private int x;
private int y;
public Rectangle(int x, int y) {
this.x = x;
this.y = y;
}
public int area() {
return x * y;
}
}
class Square {
private Rectangle rectangle;
public Square(int a) {
this.rectangle = new Rectangle(a, a);
}
public int area() {
return this.rectangle.area();
}
}
public class Main {
public static void main( String[] args ) {
int x, y;
if ( args.length > 1 ) {
x = Integer.parseInt( args[0] );
y = Integer.parseInt( args[1] );
}
else {
x = 3;
y = 7;
}
Rectangle r = new Rectangle( x, y );
System.out.println( r.area() );
Square sq1 = new Square( x );
System.out.println( sq1.area() );
Square sq2 = new Square( y );
System.out.println( sq2.area() );
}
}
I've cobbled together the following Perl/Moose/Mouse version, which I'm not sure is the right way to do things, so I'm submitting it to the judgment of the guild of experts assembled in these halls:
package Rectangle;
use Mouse;
has [ qw( x y ) ], is => 'ro', isa => 'Int';
sub area {
my( $self ) = #_;
return $self->x * $self->y;
}
package Square;
use Mouse;
has x => is => 'ro', isa => 'Int';
has rectangle => is => 'ro', isa => 'Rectangle';
# The tricky part: modify the constructor.
around BUILDARGS => sub {
my $orig = shift;
my $class = shift;
my %args = #_ == 1 ? %{ $_[0] } : #_;
$args{rectangle} = Rectangle->new( x => $args{x}, y => $args{x} );
return $class->$orig( \%args );
};
sub area { $_[0]->rectangle->area } # delegating
package main;
use strict;
my $x = shift || 3;
my $y = shift || 7;
my $r = Rectangle->new( x => $x, y => $y);
my $sq1 = Square->new( x => $x );
my $sq2 = Square->new( x => $y );
print $_->area, "\n" for $r, $sq1, $sq2;
This works, but as I haven't seen much Moose in action, I'm just not sure this is the way to go, or if there is an even easier way. Thanks for any feedback, or pointers for more Moose user-level discussion.
While I am not sure this is best practice, probably best translation I can think of would be something like this:
package Rectangle;
use Mouse;
has [ qw( x y ) ], is => 'ro', isa => 'Int';
sub area {
my( $self ) = #_;
return $self->x * $self->y;
}
package Square;
use Mouse;
has x => is => 'ro', isa => 'Int';
has rectangle =>
is => 'ro',
isa => 'Rectangle',
lazy_build => 1,
handles => [ 'area' ];
sub _build_rectangle {
my $self = shift;
Rectangle->new(x => $self->x, y => $self->x);
}
The handles in rectangle attribute automatically builds delegation to area for you.
This is how I'd do it with Moose. It's pretty much identical to the Mouse version:
use 5.012;
use Test::Most;
{
package Rectangle;
use Moose;
has [qw(x y)] => ( is => 'ro', isa => 'Int' );
sub area {
my $self = shift;
return $self->x * $self->y;
}
}
{
package Square;
use Moose;
has [qw(x y)] => ( is => 'ro', isa => 'Int' );
has rectangle =>
( isa => 'Rectangle', lazy_build => 1, handles => ['area'] );
sub _build_rectangle {
my $self = shift;
Rectangle->new( x => $self->x, y => $self->y );
}
}
my #dimensions
= ( [qw(Rectangle 3 7 21 )], [qw(Square 3 3 9 )], [qw(Square 3 7 21 )] );
for my $dimension (#dimensions) {
my ( $shape, $x, $y, $area ) = #{$dimension};
my $rect = new_ok $shape, [ x => $x, y => $y ];
is $area, $rect->area, "area of $shape ($x, $y) => $area";
}
done_testing;