Ab myty Version 4.1 ist ein Plugin System für Frontend und Teile des Backendsystems verfügbar (dieses wird in zukünftigen Versionen noch erweitert werden).
Das Artikelplugin kann Standardfunktionalitäten von Varianten und Artikeln beeinflussen hierzu zählen das Verhalten der Tag Engine bei der Ausgabe des Artikels im Frontend (in Artikellisten/Detailseiten), Warenkorbaktionen (hinzufügen/löschen/Bestandsaktualisierungen), weiterhin können zusätzliche Abhängigkeiten von Nutzerdaten geprüft werden.
Generell gilt, dass ein Plugin erst initialisiert/aufgerufen wird, wenn der entsprechende Artikel in der betreffenden Liste oder dem Warenkorb vorhanden ist. Es existiert zu jedem Zeitpunkt immer nur eine Instanz des Plugins, die betreffenden Umgebungsvariablen, wie Id des Artikels / der Variante (sofern für die Aktion möglich), werden vor dem Aufruf der Callback Methode gesetzt.
Das Plugin ist abzulegen im Ordner /tycon/modules/shop/plugins/beispielplugin.php. Die Klasse ist genauso zu benennen, wie diese php Datei. Weiterhin muss diese Klasse eine abgeleitete Klasse von tyShopArticlePlugin sein.
Die Klasse tyShopArticlePlugin implementiert alle notwendigen und möglichen Callbackmethoden des Standardverhaltens, alle Methoden können überschrieben werden und verändern damit die Standardfunktionalität des Systems an den Einsprungspunkten.
Das Plugin wird über die Artikelgruppen referenziert. Ist diese Artikelgruppe dem Artikel zugewiesen ist das Plugin für diese Artikel aktiviert. Die Einstellung wird im Shop Backend unter „Einstellungen“⇒„Einstellungen für Produktfelder“⇒„Artikel-Plugin“ getätigt, hier ist die Klasse des Plugins einzutragen, das diesen Typ von Artikel verwaltet. Tragen Sie an dieser Stelle den genauen Namen der Pluginklasse ein. Achten Sie bitte auch auf korrekte Groß- und Kleinschreibung.
class tyShopArticlePlugin{
// Standard Konstruktor mit Initialisierungsparameter
public function __construct( $optionId = null, $articleId = null ){
}
// liefert die Artikel Id oder null zurück, sofern nicht gesetzt
public function getArticleId(){
}
// setzt die Artikel Id
public function setArticleId( $newArticleId = null ){
}
// liefert die Varianten Id oder null zurück, sofern nicht gesetzt oder zum Zeitpunkt des Aufrufes nicht bekannt, da Artikelfunktionen aufgerufen werden
public function getOptionId(){
}
// setzt die Varianten Id
public function setOptionId( $newOptionId = null ){
}
// wird beim Speichern von Variantendaten im Backend aufgerufen
public function onOptionSaved( &$optionData ){
}
// wird beim Speichern von Artikeldaten im Backend aufgerufen
public function onArticleSaved( &$articleData){
}
// wird beim neu erzeugen des Suchindex für den Artikel aufgerufen
// Standardrückgabewert ist String($text)
public function &processTextForSearchIndex( &$text, &$lang, &$articleObject ){
return $text;
}
// bestimmt ob eine zusätzliche Artikelformularerweiterung für das Backend Bearbeitungsforumular möglich ist
// Standardrückgabewert ist Boolean(false)
public function hasArticleEditFields(){
return false;
}
// liefert die Artikelformularerweiterung des Backendformulars zurück. Siehe auch hasArticleEditFields()
// Standardrückgabewert ist null
public function renderArticleEditFields(){
return null;
}
// bestimmt ob eine zusätzliche Variantenformularerweiterung für das Backend Bearbeitungsforumular möglich ist
// Standardrückgabewert ist Boolean(false)
public function hasArticleOptionEditFields(){
return false;
}
// liefert die Variantenformularerweiterung des Backendformulars zurück. Siehe auch hasArticleOptionEditFields()
// Standardrückgabewert ist null
public function renderOptionEditFields(){
return null;
}
// wird im Warenkorb aufgerufen, wenn der Inhalt des Warenkorbes auf valide Daten überprüft wird
public function onValidateBasket( &$basketContent, &$basketObject ){
}
// wird im Warenkorb aufgerufen, wenn der Bestand des Artikels im Warenkorb geändert wird
public function onOptionUpdateQuantity( &$arrayId, &$basketContent, &$count, &$basketObject ){
}
// wird direkt nach onOptionUpdateQuantity aufgerufen. Prüft, ob onOptionUpdateQuantity Standard funktionalität ersetzt
// Standardrückgabewert ist Boolean(false)
public function onOptionUpdateQuantityIsHandled( &$arrayId, &$basketContent, &$count, &$basketObject );
// wird direkt nach onOptionUpdateQuantity aufgerufen. Prüft, ob onOptionUpdateQuantity Standard funktionalität ersetzt
public function onOptionUpdateQuantityIsHandled( &$arrayId, &$basketContent, &$count, &$basketObject ){
return false;
}
// wird vor dem hinzufügen eines neuen Artikels zum Warenkorb aufgerufen
public function onOptionAddToBasket( &$option, &$count, &$basketObject ){
return null;
}
// wird direkt nach onOptionAddToBasket aufgerufen. Prüft, ob onOptionAddToBasket Standard funktionalität ersetzt
// Standard Rückgabewert ist false => Artikel wird normal vom Warenkorb behandelt
public function onOptionAddToBasketIsHandled( &$option, &$count, &$basketObject ){
return false;
}
// wird nach dem hinzufügen zum Warenkorb aufgerufen
public function onOptionAddedToBasket( &$arrayId, &$basketContent, &$basketObject ){
return null;
}
// wird im Warenkorb benötigt um die maximal zulässige Artikelmenge zu bestimmen, die in den Warenkorb gelegt werden darf
public function getMaxAddCountForBasket( &$option, &$orgCount, &$basket, &$basketObject ){
return $orgCount;
}
// wird direkt nach getMaxAddCountForBasket aufgerufen. Prüft, ob Standard funktionalität von getMaxAddCount ersetzt wird
// Standard Rückgabewert ist false => Artikel wird normal behandelt
public function getMaxAddCountForBasketIsHandled( &$option, &$count, &$basket, &$basketObject ){
return false;
}
// wird im Warenkorb benötigt um die maximal zulässige Artikelmenge zu bestimmen, die in den Warenkorb gelegt werden darf. Bitte beachten Sie auch getMaxOrderCountForOptionIsHandled
public function getMaxOrderCountForOption( &$orgCount, &$option, &$article ){
return $orgCount;
}
// wird direkt nach getMaxOrderCountForOption aufgerufen. Prüft, ob Standard funktionalität von getMaxOrderCount der Variante ersetzt wird
// Standard Rückgabewert ist false => Standardscript wird normal weiter verarbeitet
public function getMaxOrderCountForOptionIsHandled( &$count, &$option, &$article ){
return false;
}
// wird aufgerufen, wenn auf den Warenkorb eine Löschaktion ausgeführt werden soll
public function onRemoveFromBasket(&$arrayId, &$basketContent, &$basketObject){
return null;
}
// wird direkt nach onRemoveFromBasket aufgerufen, prüft ob Standardprozess ersetzt werden soll
public function onRemoveFromBasketIsHandled(&$arrayId, &$basketContent, &$basketObject){
return false;
}
// wird aufgerufen, wenn das Produkt im Warenkorb vorhanden ist und die Nutzerdaten gespeichert wurden
public function onBasketUserdataChanged( &$user ){
}
// Callbackfunktion, wird zu Beginn der Abarbeitung des Nutzerdatenvalidierungs Scripts ausgeführt
public function onCustomerFormHandlerBegin( &$handler ){
}
// Callbackfunktion, wird vor Ende der Abarbeitung des Nutzerdatenvalidierungs Scripts ausgeführt
public function onCustomerFormHandlerEnd( &$handler ){
}
// Callbackfunktion, wird ausgeführt wenn Nutzerdatenformular korrekt validiert werden konnte und keine Fehler aufgetreten sind
public function onCustomerFormHandlerSuccess( &$handler ){
}
// Callbackfunktion, wird ausgeführt wenn Nutzerdatenformular nicht validiert werden konnte und Fehler aufgetreten sind
public function onCustomerFormHandlerFailed( &$handler ){
}
// wird nach dem Bestellen und Speichern der aktuellen Bestellung durchgeführt
public function onOrderStored( &$orderId, &$sessionBasket, &$sessionOrder ){
}
// wird beim Überprüfen der aktuellen Bestellung durchgeführt
// der Rückgabewert ist zwingend erforderlich
public function onCheckOrderContents( &$check_result, &$action, &$sessionOrder, &$sessionUser, &$orderHandler ){
return $check_result;
}
// filtert die Artikelliste
public function filterArticleListForTagEngine( &$listOfArticle, $articleList ){
}
// Artikelerweiterung für Tagengine
public function parseArticleBeforeTagengine( &$substitution, &$tag_parsed, &$articleObject, &$articleTagClass){
}
// Artikelerweiterung für Tagengine
public function parseArticleAfterTagengine( &$substitution, &$tag_parsed, &$articleObject, &$articleTagClass){
}
// Varianten
// kann Varianten vor dem ausgeben der Artikelvarianten in der Tagengine filtern
public function filterArticleOptionsForTagEngine( &$substitution, &$tag_parsed, &$articleOptions, $articleTagClass ){
}
// Varianten Tags (vor Tagverarbeitung)
public function parseOptionBeforeTagengine( &$substitution, &$tag_parsed, &$optionObject, &$optionTagClass){
}
// Varianten Tags (nach Tagverarbeitung)
public function parseOptionAfterTagengine( &$substitution, &$tag_parsed, &$optionObject, &$optionTagClass){
}
// BasketProduct Tags (vor Tagverarbeitung)
public function parseBasketProductTagBeforeTagengine( &$substitution_src, &$tag_parsed, &$optionObject, &$basketTagClass){
}
// BasketProduct Tags (nach Tagverarbeitung)
public function parseBasketProductTagAfterTagengine( &$substitution_src, &$tag_parsed, &$optionObject, &$basketTagClass){
}
// bestimmt, ob der 'in den Warenkorb legen' - Button angezeigt werden soll
// Rückgabewerte true|false|null
public function showToBasketButton(){
return null;
}
// bestimmt, ob der Anfrage Button angezeigt werden darf
public function showToRequestButton(){
return null;
}
}
Funktion des Plugins:
class beispielplugin extends tyShopArticlePlugin{
public function __construct( $optionId = null, $articleId = null ){
parent::__construct( $optionId, $articleId );
// remove Session Data
if( $GLOBALS['tyState']['topic'] != TY_SHOP_ORDER_CHECK_TOPIC &&
$GLOBALS['tyState']['topic'] != TY_SHOP_ORDER_CONFIRMATION_TOPIC &&
$GLOBALS['tyState']['topic'] != '' ){
unset( $_SESSION['userHasOrdered'] );
unset( $_SESSION['singleProductInBasket'] );
}
unset( $_SESSION['setQuantityFailed'] );
unset( $_SESSION['setQuantityFailedMaxQuantity'] );
unset( $_SESSION['setQuantityFailedMinQuantity'] );
}
public function hasArticleOptionEditFields(){
return true;
}
public function checkDB(){
try{
tyDB::exec("CREATE TABLE IF NOT EXISTS `shop_plugin_beispielplugin` (
`id` int(11) NOT NULL default '0',
`minOrderCount` float NOT NULL default '0',
`maxOrderCount` float NOT NULL default '1',
UNIQUE KEY `option_id` (`id`)
)");
tyDB::exec("CREATE TABLE IF NOT EXISTS `shop_plugin_beispielplugin_ordered` (
`orderId` int(11) NOT NULL default '0',
`firstname` varchar(255) NOT NULL default '',
`lastname` varchar(255) NOT NULL default '',
`city` varchar(255) NOT NULL default '',
`address` varchar(255) NOT NULL default '',
`address_nr` varchar(255) NOT NULL default '',
`email` varchar(255) NOT NULL default '',
UNIQUE KEY `IdxOrderId` (`orderId`),
KEY `IdxFirstname` (`firstname`),
KEY `IdxLastname` (`lastname`),
KEY `IdxEmail` (`email`),
KEY `IdxAddress` (`address`),
KEY `IdxCity` (`city`)
)");
}catch(Exception $e){
}
}
public function onCheckOrderContents( &$check_result, &$action, &$sessionOrder, &$sessionUser, &$orderHandler ){
$this->removeSingleProductInBasket();
if( strtolower($action) == 'submitorder' ){
if( $_SESSION[SW_SHOP_SESSION_BASKET_ID]["customer_data"]['acceptAdditionalAGB'] != 1 && count($this->getOptionIdsInBasket())>0 ){
$check_result = false;
}
}
return $check_result;
}
public function onOptionSaved( $optionData ){
try{
$this->checkDB();
if(isset($_REQUEST['shopPlugin']['options'][$this->getOptionId()]) && is_array($_REQUEST['shopPlugin']['options'][$this->getOptionId()])){
if($_REQUEST['shopPlugin']['options'][$this->getOptionId()]['minOrderCount']!=='' && $_REQUEST['shopPlugin']['options'][$this->getOptionId()]['maxOrderCount']!==''){
$row = array();
$row['id'] = $this->getOptionId(); // option_id
$row['minOrderCount'] = $_REQUEST['shopPlugin']['options'][$this->getOptionId()]['minOrderCount']; // min Order Count
$row['maxOrderCount'] = $_REQUEST['shopPlugin']['options'][$this->getOptionId()]['maxOrderCount']; // max Order Count
$qf = new tyDBQueryField( $row );
tyDB::insertUpdate('shop_plugin_beispielplugin', $qf);
}else{
tyDB::exec( "DELETE FROM shop_plugin_beispielplugin WHERE id=" . (int)$this->getOptionId() );
}
}
}catch(Exception $e){
}
}
public function getData(){
try{
$this->checkDB();
return tyDB::fetchAssoc(tyDB::query('SELECT * FROM shop_plugin_beispielplugin WHERE id=' . (int)$this->getOptionId() . " LIMIT 1"));
}catch(Exception $e){
}
return false;
}
public function parseArticleBeforeTagengine(&$substitution, &$tag_parsed, &$articleObject, &$articleTagClass){
}
public function parseOptionBeforeTagengine(&$substitution, &$tag_parsed, &$optionObject, &$optionTagClass){
switch($tag_parsed["element"]) {
case 'optionGoToOption':
$subst = $tag_parsed["substitution"];
$subtag = clone $optionTagClass;
$subtag->swShop_OptionTag($subst, $optionTagClass->option, $optionTagClass->parent_article);
$pm = $optionTagClass->parseMode;
$subtag->switchParseMode('html');
$subtag_parsed = $subtag->parse();
$optionTagClass->switchParseMode($pm);
if (is_array($subtag_parsed)) {
foreach( $subtag_parsed as $code => $value ) {
$subst = str_replace($code, $value, $subst);
}
} else {
$subst = $subtag_parsed;
}
$substitution = str_replace($tag_parsed['code'],'<a href="' . tyGetURLByTopic('tyNavigationTopicID_990') . '">' . $subst . '</a>',$substitution);
break;
}
}
public function onOrderStored( &$orderId, &$sessionBasket, &$sessionOrder ){
try{
$this->checkDB();
$row = array();
$row['orderId'] = $orderId;
$row['firstname'] = trim(strtolower($sessionOrder->basket->data['customer_data']['firstname']));
$row['lastname'] = trim(strtolower($sessionOrder->basket->data['customer_data']['lastname']));
$row['city'] = trim(strtolower($sessionOrder->basket->data['customer_data']['city']));
$row['address'] = trim(strtolower($sessionOrder->basket->data['customer_data']['address']));
$row['address_nr'] = trim(strtolower($sessionOrder->basket->data['customer_data']['address_nr']));
$row['email'] = trim(strtolower($sessionOrder->basket->data['customer_data']['email']));
$qf = new tyDBQueryField( $row );
tyDB::insertUpdate('shop_plugin_beispielplugin_ordered', $qf);
}catch(Exception $e){
trigger_error($e->getMessage());
}
}
public function userHasOrdereded(){
if(is_object($GLOBALS['swShop_Basket'])){
if(class_exists('swShop_SessionUser')){
$user = new swShop_SessionUser();
if( $user->getFirstName() != '' &&
$user->getLastName() != '' &&
$user->getCity() != '' &&
$user->getAddress()!=''
){
try{
$this->checkDB();
$row = tyDB::fetchAssoc(tyDB::query(
" SELECT orderId
FROM shop_plugin_beispielplugin_ordered
WHERE
firstname='" . tyDB::escapeValue( trim(strtolower($user->getFirstName())) ) . "' AND
lastname='" . tyDB::escapeValue( trim(strtolower($user->getLastName())) ) . "' AND
city='" . tyDB::escapeValue( trim(strtolower($user->getCity())) ) . "' AND
address='" . tyDB::escapeValue( trim(strtolower($user->getAddress())) ) . "' AND
address_nr='" . tyDB::escapeValue( trim(strtolower($user->getAddressNr())) ) . "'
LIMIT 1
"
));
if( is_array($row) ){
$_SESSION['userHasOrdered'] = true;
return true;
}
$_SESSION['userHasOrdered'] = false;
return false;
}catch(Exception $e){
trigger_error("fehler 51101 im Beispielplugin festgestellt");
}
}
}
}
return false;
}
public function renderOptionEditFields(){
$data = $this->getData();
$result = '<tr><td>' . ty_("min. bestellbare Menge dieses Artikels je Nutzer") . '</td><td><input type="text" name="shopPlugin[options][' . $this->getOptionId() . '][minOrderCount]" value="' . $data['minOrderCount'] . '" class="tyFormText"/></td></tr>';
$result.= '<tr><td>' . ty_("max. bestellbare Menge dieses Artikels je Nutzer") . '</td><td><input type="text" name="shopPlugin[options][' . $this->getOptionId() . '][maxOrderCount]" value="' . $data['maxOrderCount'] . '" class="tyFormText"/></td></tr>';
return $result;
}
// liefert alle Varianten Ids im Warenkorb zurück
public function getOptionIdsInBasket(){
$filteredOptIds = array();
if(is_object($GLOBALS['swShop_Basket'])){
// entfernen des Artikels aus allen Listen, wenn dieser im WK vorhanden ist
$basketContent = $GLOBALS['swShop_Basket']->getContent();
$optIds = array();
foreach( array_keys($basketContent) as $basketIdx){
if( isset($basketContent[$basketIdx]['data']) && $basketContent[$basketIdx]['data']['id'] > 0 ){
$optIds[(int)$basketContent[$basketIdx]['data']['id']] = (int)$basketContent[$basketIdx]['data']['id'];
}
}
if(count($optIds)>0){
try{
$qres = tyDB::query("SELECT
DISTINCT shop_article_options.id
FROM shop_articles_setup
INNER JOIN shop_articles
ON shop_articles.group_id=shop_articles_setup.group_id
INNER JOIN shop_article_options
ON shop_articles.id=shop_article_options.art_id AND shop_article_options.id IN ('" . implode("','",$optIds) . "')
WHERE
shop_articles_setup.value = 'beispielplugin' AND
shop_articles_setup.name = 'article_plugin_class'");
while($row = tyDB::fetchAssoc($qres)){
$filteredOptIds[$row['id']] = $row['id'];
}
}catch(Exception $e){
trigger_error( $e->getMessage() );
}
}
}
return $filteredOptIds;
}
public function filterArticleListForTagEngine( &$list, &$tagParser ){
if(is_object($GLOBALS['swShop_Basket'])){
// entfernen des Artikels aus allen Listen, wenn dieser im WK vorhanden ist
$basketContent = $GLOBALS['swShop_Basket']->getContent();
$optIds = array();
foreach( array_keys($basketContent) as $basketIdx){
if( isset($basketContent[$basketIdx]['data']) && $basketContent[$basketIdx]['data']['id'] > 0 ){
$optIds[(int)$basketContent[$basketIdx]['data']['id']] = (int)$basketContent[$basketIdx]['data']['id'];
}
}
$filteredArtIds = array();
if( count($optIds)>0 || $this->userHasOrdereded() ){
try{
$qres = tyDB::query("SELECT
DISTINCT shop_articles.id
FROM shop_articles_setup
INNER JOIN shop_articles
ON shop_articles.group_id=shop_articles_setup.group_id
INNER JOIN shop_article_options
ON shop_articles.id=shop_article_options.art_id" . (count($optIds)>0?" AND shop_article_options.id IN ('" . implode("','",$optIds) . "')":"") . "
WHERE
shop_articles_setup.value = 'beispielplugin' AND
shop_articles_setup.name = 'article_plugin_class'");
while($row = tyDB::fetchAssoc($qres)){
$filteredArtIds[$row['id']] = $row['id'];
}
}catch(Exception $e){
trigger_error( $e->getMessage() );
}
}
if(count($filteredArtIds)>0){
$akeys = array_keys($list);
foreach($akeys as $key){
if( isset( $filteredArtIds[ $list[ $key ]->getId() ] ) ){
unset( $list[$key] );
}
}
}
}
}
public function removeSingleProductInBasket(){
if(is_object($GLOBALS['swShop_Basket'])){
$optIds = $this->getOptionIdsInBasket();
$bContent = $GLOBALS['swShop_Basket']->getContent();
if( count( $bContent ) - count( $optIds ) <= 0 ){
foreach( $bContent as $idx=>$content ){
if(in_array($content['data']['id'],$optIds)){
$_SESSION['singleProductInBasket'] = true;
$GLOBALS['swShop_Basket']->updateQuantity( $content['data']['id'], 0, false, $idx );
}
}
}
}
}
// wird aufgerufen, wenn das Produkt im Warenkorb vorhanden ist und die Nutzerdaten gespeichert wurden
public function onBasketUserdataChanged( &$user ){
if( $this->userHasOrdereded() ){
// wenn nutzer bereits bestellt hat, Artikel aus dem Warenkorb entfernen
foreach( $this->getOptionIdsInBasket() as $optId ){
$GLOBALS['swShop_Basket']->updateQuantity( $optId, 0 );
}
}
$this->removeSingleProductInBasket();
}
public function filterArticleOptionsForTagEngine( &$substitution, &$tag_parsed, &$articleOptions, $articleTagClass ){
}
public function onCustomerFormHandlerBegin( &$handler ){
if(count($this->getOptionIdsInBasket())>0 && isset($_REQUEST['tyForms']['shop_customer_form']['acceptAdditionalAGB'])){
if( !$_REQUEST['tyForms']['shop_customer_form']['acceptAdditionalAGB'] ){
$handler->bad_fields[] = 'acceptAdditionalAGB';
$_SESSION[SW_SHOP_SESSION_BASKET_ID]["customer_data"]['acceptAdditionalAGB'] = '0';
}else{
$_SESSION[SW_SHOP_SESSION_BASKET_ID]["customer_data"]['acceptAdditionalAGB'] = '1';
}
}
}
public function onOptionUpdateQuantity( &$basket_idx, &$content, &$count, &$basket ){
// es sind nur X Artikel zulässig
$this->setOptionId($content[$basket_idx]['data']['id']);
$dbData = $this->getData();
if(is_array($dbData)){
if( $dbData['minOrderCount'] <= $dbData['maxOrderCount'] && $dbData['maxOrderCount']>0 ){
if( $count < $dbData['minOrderCount'] ){
$_SESSION['setQuantityFailed'] = true;
$_SESSION['setQuantityFailedMinQuantity'] = true;
$count = $dbData['minOrderCount'];
}
if( $count > $dbData['maxOrderCount'] ){
$_SESSION['setQuantityFailed'] = true;
$_SESSION['setQuantityFailedMaxQuantity'] = true;
$count = $dbData['maxOrderCount'];
}
}
}
// TODO Prüfung, ob Nutzer bereits bestellt hat
if( $count > 0 && $this->userHasOrdereded() ){
$count = 0;
}
}
public function showToBasketButton(){
//return rand(0,1)==1;
if(is_object($GLOBALS['swShop_Basket'])){
// Bestell-Button ausblenden, wenn dieser Artikel bereits im WK vorhanden
$basketContent = $GLOBALS['swShop_Basket']->getContent();
if( $this->userHasOrdereded() ){
return false;
}
$optIds = array();
foreach( array_keys($basketContent) as $basketIdx){
if( isset($basketContent[$basketIdx]['data']) && $basketContent[$basketIdx]['data']['id'] > 0 ){
if($this->getOptionId() == (int)$basketContent[$basketIdx]['data']['id']){
return false;
}
}
}
}
return null;
}
public function showToRequestButton(){
return null;
}
}