I'm developing a custom module for add a button "notify me" when product is out of stock.
this button should simply call an action and write in a custom table (created by this module)
my problem is pass the id_product to the hook
public function install() {
$sql= "CREATE TABLE IF NOT EXISTS `"._DB_PREFIX_."fasys_notify`(
`id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`title` VARCHAR(256) NOT NULL )";
if (parent::install() == false ||
!$this->registerHook('notify') ||
!$this->registerHook('displayHeader') ||
!Db::getInstance()->Execute($sql)
)
return false;
return true;
}
public function hookFasysNotify($params) {
//NEED ID_PRODUCT HERE
//var_dump(Tools::getValue('id_product')); //doesen't works
$html ='<button type="button" class="notifyme_btn btn btn-info btn-default">Notify Me</button>';
return $html ;
}
in my .tpl file i have added this:
{hook h='fasysNotify' product=$product}
how can I retrieve the product ?
.tpl
{hook h='fasysNotify' product=$product}
module:
public function hookNotify($params) {
var_dump( $params['product'] );
}
in tpl :
{hook h='fasysNotify' product=$product}
or
{hook h='fasysNotify' product=$id_product}
in module :
$id_product = $param['id_product'];
or
$id_product = $param;
Related
I am working on a function to find a field from any form based on the label text. I'd like to return different attributes of the field so that I can use them later.
Originally, I just needed the value of the field, so I used the work here to return the value of a field based on the label:
function itsg_get_value_by_label( $form, $entry, $label ) {
foreach ( $form['fields'] as $field ) {
$lead_key = $field->label;
if ( strToLower( $lead_key ) == strToLower( $label ) ) {
return $entry[ $field->id ];
}
}
return false;
}
I get my value by setting a variable and passing in the field label that I'm looking for:
$mobile_phone = itsg_get_value_by_label( $form, $entry, "Mobile Phone" );
Later on, as I continued to work on my solution, I found that I also needed to find those fields and return the ID. Initially, I wrote the same function and just returned the ID, but I'd like to make the solution more efficient by rewriting the function to return multiple field attributes in an array, as such:
function get_field_atts_by_label( $form, $entry, $label ) {
foreach ( $form['fields'] as $field ) {
$lead_key = $field->label;
if ( strToLower( $lead_key ) == strToLower( $label ) ) {
$field_atts = array(
'value' => $entry[ $field->id ],
'id' => $field->id,
);
return $field_atts;
}
}
return false;
}
My problem now is that I am not quite sure how to retrieve the specific attributes from my function and set them to a variable.
Well, I'll go ahead and answer my own question. Such a simple solution to this one. Had a momentary brain fart.
$mobile_phone = get_field_atts_by_label( $form, $entry, "Mobile Phone" );
$mobile_phone_id = $mobile_phone['id'];
$mobile_phone_value = $mobile_phone['value'];
I have created a model and added the $has_many for selecting multiple products. This is working fine but I am unable to make the selected products sortable by drag and drop. I know this is possible I have seen it. But I am unable to find anything in the documentation that shows how to get this done. Here is my model:
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
require_once(FUEL_PATH.'models/Base_module_model.php');
/**
* This model handles setting up the form fields for our contact form
*
*/
class Products_category_model extends Base_module_model {
public $required = array('name', 'published');
public $has_many = array('products' => array(FUEL_FOLDER => 'Products_model'));
function __construct()
{
parent::__construct('w_product_categories');
}
/*
This will provide the list of records for display in the Admin Panel
Note how the "excerpt" will display, but truncated
Because we are using some MySQL functions in our select statement,
we pass FALSE in as the second parament to prevent CI auto escaping of fields
*/
function list_items($limit = null, $offset = null, $col = 'name', $order = 'asc', $just_count = false)
{
$this->db->select('id, name, published', FALSE);
$data = parent::list_items($limit, $offset, $col, $order);
return $data;
}
function form_fields($values = array(), $related = array())
{
$fields = parent::form_fields($values, $related);
return $fields;
}
}
class Product_category_model extends Base_module_record {
}
So it is very simple I discovered. I added this in the form fields function:
// Makes the has many drag and drop sortable.
$fields['products']['sorting'] = TRUE;
$fields['products']['after_html'] = "<div style=\"clear:both;font-style:italic\">NOTE: you can sort selected product to your choosing by clicking on the product and then dragging it into the desired placement in the list</div>";
I have :
a 3 level menu
custom records from a table called
"tx_products_domain_model_product"
products have a field called "url_alias"
On any page on that menu, I can have a product record.
For pages that have a product record I want the link to look like:
http://www.sitedomain.com/<url_alias>
Can this be done with typoscript?
EDIT
It looks like it's too complex to do all this with typoscript, so I'm using a userFunc. I'm checking if there is a product record with a shop ID and want to return that shop id. If not, return the current menu page UID. The problem is, how can I pass the menu page UID as parameter to the userFunc?
class user_productsOnCurrentPage
{
function main( $content, $conf )
{
if ( TYPO3_MODE !== 'FE' )
{
return FALSE;
}
$product = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
'shop_id', 'tx_products_domain_model_product', 'pid=' . $conf['currentPageId'] . ' AND deleted=0 AND hidden=0' );
if ( is_array( $product ) && ! empty( $product ['shop_id'] ) )
{
return $product ['shop_id'];
}
return $conf['currentPageId'];
}
}
The menu:
lib.mainMenu = HMENU
lib.mainMenu {
...
1 = TMENU
1 {
...
NO = 1
NO {
...
# show direct url for external links
doNotLinkIt = 1
stdWrap.cObject = CASE
stdWrap.cObject {
key.field = doktype
default = TEXT
default {
field = nav_title // title
typolink.parameter.cObject = USER
typolink.parameter.cObject {
userFunc = user_productsOnCurrentPage->main
currentPageId = ?????
}
typolink.wrap = |<span><strong></strong></span>
typolink.ATagBeforeWrap = 1
stdWrap.htmlSpecialChars = 1
}
...
I could access the page ID directly in the user function:
TypoScript:
typolink.userFunc = user_mcfazabosOnCurrentPage->main
PHP:
$pageId = $this->cObj->getFieldVal( 'uid' );
I wish to override the title for the sitemap node, but only in the breadcrumb, not in the menu.
[Route("{partyAccountNumber}")]
[SiteMapTitle("DisplayName", Target = AttributeTarget.CurrentNode)]
public ActionResult Advice(string partyAccountNumber)
How do I use this overridden title, but only in the breadcrumb, and not in the menu.
You can put conditional logic on the title by editing the /Views/Shared/DisplayTemplates/SiteMapNodeModel.cshtml file directly.
#model MvcSiteMapProvider.Web.Html.Models.SiteMapNodeModel
#using System.Web.Mvc.Html
#using MvcSiteMapProvider.Web.Html.Models
#* Conditionally set the title based on a custom attribute *#
#{ var title = Model.Title; }
#if (Model.SourceMetadata["HtmlHelper"].ToString() == "MvcSiteMapProvider.Web.Html.SiteMapPathHelper" &&
Model.Attributes.ContainsKey("breadcrumbTitle") &&
!string.IsNullOrEmpty(Model.Attributes["breadcrumbTitle"].ToString()))
{
title = Model.Attributes["breadcrumbTitle"].ToString();
}
#if (Model.IsCurrentNode && Model.SourceMetadata["HtmlHelper"].ToString() != "MvcSiteMapProvider.Web.Html.MenuHelper") {
<text>#title</text>
} else if (Model.IsClickable) {
if (string.IsNullOrEmpty(Model.Description))
{
#title
}
else
{
#title
}
} else {
<text>#title</text>
}
On your node, you could set a custom attribute to provide the alternate value for the breadcrumb trail. If desired, you can also load the titles from a dynamic source, such as a database by using a dynamic node provider.
public class MyDynamicNodeProvider : DynamicNodeProviderBase
{
public override IEnumerable<DynamicNode> GetDynamicNodeCollection(ISiteMapNode node)
{
// Entities would be your entity framework context class
// or repository.
using (var entities = new Entities())
{
// Create a node for each item (data row in the table)
foreach (var item in entities.Items)
{
DynamicNode dynamicNode = new DynamicNode();
dynamicNode.Title = item.Title;
// Provide a custom attribute for the breadcrumb title.
dynamicNode.Attributes.Add("breadcrumbTitle", item.BreadcrumbTitle);
dynamicNode.ParentKey = "Home";
dynamicNode.Key = "Item_" + item.Id;
dynamicNode.Controller = "Item";
dynamicNode.Action = "Advice";
// custom route values must be manually accounted for by using
// RouteValues or PreservedRouteParameters.
dynamicNode.RouteValues.Add("partyAccountNumber", item.PartyAccountNumber);
//dynamicNode.PreservedRouteParameters.Add("partyAccountNumber");
yield return dynamicNode;
}
}
}
}
And then wire your dynamic node provider into your node configuration.
// Set a key explicitly to attach the dynamic nodes to.
// The key property here corresponds to the ParentKey property of the dynamic node.
<mvcSiteMapNode title="Home" controller="Home" action="Index" key="Home">
// Use a "dummy" node for the dynamic node provider. This node won't be in the SiteMap.
<mvcSiteMapNode dynamicNodeProvider="NamespaceName.MyDynamicNodeProivder, AssemblyName"/>
</mvcSiteMapNode>
I am allowing deletion of attachments in the File Download control. If a user deletes an attachment and navigates away from the page (without saving), the attachment does not actually get removed.
There is an onclick event for the control, but it isn't specific to deletion. Is there a way to automatically call a .save() after deletion of an attachment?
Here is a SSJS snippet which allows to add an action to the delete function of a FileDownload control.
<xp:this.beforeRenderResponse>
<![CDATA[#{javascript:
/***
* adds an additional method to "delete action"
* of a UIFileDownload control
*
* #param UIFileDownload component
* #author Sven Hasselbach
* #category SSJS
* #category UI
* #version 0.3
*/
function overrideFileDownloadAction( fDownload ){
if( fDownload === null )
return;
rekOverrideFileDownloadAction( fDownload, fDownload );
}
function rekOverrideFileDownloadAction( component:javax.faces.component.UIOutput, fDownload:com.ibm.xsp.component.UIFileDownload ){
try{
var children:java.util.List = component.getChildren();
var it:java.util.Iterator = children.iterator();
var curChild:javax.faces.component.UIOutput;
while( it.hasNext() ){
curChild = it.next();
if( typeof( curChild ) === 'com.ibm.xsp.component.xp.XspEventHandler' ){
var group = new com.ibm.xsp.actions.ActionGroup();
var list = new java.util.ArrayList();
group.setComponent( fDownload );
list.add( curChild.getAction() );
list.add( mBinding );
group.setActions( list );
curChild.setAction(group);
}
rekOverrideFileDownloadAction( curChild , fDownload );
}
}catch(e){}
}
var mBinding = facesContext.getApplication().createMethodBinding("#{javascript:document1.save()}", null );
overrideFileDownloadAction( getComponent( 'fileDownload1' ) );
}]]>
</xp:this.beforeRenderResponse>
You have to change the code in the MethodBinding mBinding and the name of the FileDownLoad control. Please keep in mind that this code will only save the document if there are no validation problems. To disable required fields you have to add the following line of code curChild.setDisableValidators( true ); in the if block.
An alternative is to use the enableModifiedFlag property to ensure that the user is prompted if leaving the page without saving.
More details at http://publib.boulder.ibm.com/infocenter/domhelp/v8r0/topic/com.ibm.designer.domino.ui.doc/wpd_controls_pref_enablemodifiedflag.html