Multiple Site 1 Basket / Checkout
Forum rules
Always add your TYPO3, Aimeos and PHP version as well as your environment (Linux/Mac/Win)
Spam and unrelated posts will be removed immediately!
Always add your TYPO3, Aimeos and PHP version as well as your environment (Linux/Mac/Win)
Spam and unrelated posts will be removed immediately!
Re: Multiple Site 1 Basket / Checkout
Maybe you want to share your code to support the project 

Professional support and custom implementation are available at Aimeos.com
If you like Aimeos,
give us a star
If you like Aimeos,

Re: Multiple Site 1 Basket / Checkout
i still have some problems, if i fixed them i will post it here.
Re: Multiple Site 1 Basket / Checkout
Hello Admin and community,
I had holidays and after them some other projects to work on, so my late replie.
I now made an editable tree for locale site's like catalog has one. The tree holds all childs of my default site (my market place).
Item Class
Path: ext/myext/Resources/Private/Extensions/myext/lib/custom/src/MShop/Locale/Item/Site/Nodesites.php
Manager
Path:ext/myext/Resources/Private/Extensions/myext/lib/custom/src/MShop/Locale/Manager/Site/Nodesites.php
I had holidays and after them some other projects to work on, so my late replie.
I now made an editable tree for locale site's like catalog has one. The tree holds all childs of my default site (my market place).
Item Class
Path: ext/myext/Resources/Private/Extensions/myext/lib/custom/src/MShop/Locale/Item/Site/Nodesites.php
Code: Select all
<?php
/**
* @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
* @copyright Metaways Infosystems GmbH, 2011
* @copyright Aimeos (aimeos.org), 2015-2017
* @package MShop
* @subpackage Locale
*/
namespace Aimeos\MShop\Locale\Item\Site;
/**
* Default implementation of a Site item.
*
* @package MShop
* @subpackage Locale
*/
class Nodesites
extends \Aimeos\MShop\Common\Item\Base
//extends \Aimeos\MShop\Common\Item\ListRef\Base
implements \Aimeos\MShop\Locale\Item\Site\Iface
{
private $node;
private $children;
/**
* Initializes the site object.
*
* @param \Aimeos\MW\Tree\Node\Iface $node Tree node
* @param array $children List of nodes implementing \Aimeos\MW\Tree\Node\Iface
*/
public function __construct( \Aimeos\MW\Tree\Node\Iface $node, array $children = [])
{
\Aimeos\MW\Common\Base::checkClassList( '\\Aimeos\\MShop\\Locale\\Item\\Site\\Iface', $children );
parent::__construct('locale.site.', [] );
$this->node = $node;
$this->children = $children;
}
/**
* Sets the item values from the given array.
*
* @param array $list Associative list of item keys and their values
* @return array Associative list of keys and their values that are unknown
*/
public function fromArray( array $list )
{
$unknown = [];
$list = parent::fromArray( $list );
foreach( $list as $key => $value )
{
switch( $key )
{
case 'locale.site.id': $this->setId( $value ); break;
case 'locale.site.code': $this->setCode( $value ); break;
case 'locale.site.label': $this->setLabel( $value ); break;
case 'locale.site.status': $this->setStatus( $value ); break;
case 'locale.site.config': $this->setConfig( $value ); break;
case 'locale.site.target': $this->setTarget( $value ); break;
//case 'locale.site.parentid': $this->setParentId($value); break;
default: $unknown[$key] = $value;
}
}
return $unknown;
}
/**
* Returns the item values as array.
*
* @param boolean True to return private properties, false for public only
* @return array Associative list of item properties and their values
*/
public function toArray( $private = false )
{
$list = [
'locale.site.code' => $this->getCode(),
'locale.site.label' => $this->getLabel(),
'locale.site.config' => $this->getConfig(),
'locale.site.status' => $this->getStatus(),
'locale.site.hasChildren' => $this->hasChildren(),
];
if( $private === true )
{
$list['locale.site.id'] = $this->getId();
$list['locale.site.siteid'] = $this->getSiteId();
$list['locale.site.target'] = $this->getTarget();
$list['locale.site.level'] = $this->getLevel();
$list['locale.site.parentid'] = $this->getParentId();
$list['locale.site.ctime'] = $this->getTimeCreated();
$list['locale.site.mtime'] = $this->getTimeModified();
$list['locale.site.editor'] = $this->getEditor();
}
return $list;
}
/**
* Returns a child of this node identified by its index.
*
* @param integer $index Index of child node
* @return \Aimeos\MShop\Locale\Item\Site\Iface Selected node
*/
public function getChild( $index )
{
if( isset( $this->children[$index] ) ) {
return $this->children[$index];
}
throw new \Aimeos\MShop\Catalog\Exception( sprintf( 'Child node with index "%1$d" not available', $index ) );
}
/**
* Returns all children of this node.
*
* @return array Numerically indexed list of nodes
*/
public function getChildren()
{
return $this->children;
}
/**
* Tests if a node has children.
*
* @return boolean True if node has children, false if not
*/
public function hasChildren()
{
if( count( $this->children ) > 0 ) {
return true;
}
return $this->node->hasChildren();
}
/**
* Adds a child node to this node.
*
* @param \Aimeos\MShop\Common\Item\Tree\Iface $item Child node to add
*/
public function addChild( \Aimeos\MShop\Common\Item\Tree\Iface $item )
{
// don't set the modified flag as it's only for the values
$this->children[] = $item;
return $this;
}
/**
* This is wrong but because i extend standard but this is not working
*
*/
/**
* Creates a deep clone of all objects
*/
public function __clone()
{
$this->node = clone $this->node;
}
/**
* Returns the id of the site.
*
* @return integer|null Id of the site
*/
public function getId()
{
return $this->node->getId();
}
/**
* Sets the unique ID of the node.
*
* @param string|null Unique ID of the node
* @return \Aimeos\MShop\Catalog\Item\Iface Catalog item for chaining method calls
*/
public function setId( $id )
{
if( $id === $this->getId() ) { return $this; }
$this->node->setId( $id );
}
/**
* Returns the site ID of the item.
*
* @return integer|null Site ID of the item
*/
public function getSiteId()
{
return ( $this->node->__isset( 'locale.site.siteid' ) ? $this->node->__get( 'locale.site.siteid' ) : null );
}
/**
* Returns the code of the site.
*
* @return string Returns the code of the item
*/
public function getCode()
{
return $this->node->getCode();
}
/**
* Sets the code of the site.
*
* @param string $code The code to set
* @return \Aimeos\MShop\Locale\Item\Site\Iface Locale site item for chaining method calls
*/
public function setCode( $code )
{
if( (string) $code !== $this->getCode() ) {
$this->node->setCode( $this->checkCode( (string) $code ) );
}
return $this;
}
/**
* Returns the config property of the site.
*
* @return array Returns the config of the Site
*/
public function getConfig()
{
return $this->node->__isset( 'config' ) && is_array( $this->node->config ) ? $this->node->__get( 'config' ) : [];
}
/**
* Sets the config property of the site.
*
* @param array $options Options to be set for the Site
* @return \Aimeos\MShop\Locale\Item\Site\Iface Locale site item for chaining method calls
*/
public function setConfig( array $options )
{
$this->node->__set( 'config', $options );
return $this;
}
/**
* Returns the label property of the site.
*
* @return string Returns the label of the Site
*/
public function getLabel()
{
return $this->node->getLabel();
}
/**
* Sets the label property of the site.
*
* @param string $label The label of the Site
* @return \Aimeos\MShop\Locale\Item\Site\Iface Locale site item for chaining method calls
*/
public function setLabel( $label )
{
if( (string) $label !== $this->getLabel() )
{
$this->node->setLabel( (string) $label );
}
return $this;
}
/**
* Returns the URL target specific for that category
*
* @return string URL target specific for that category
*/
public function getTarget()
{
return ( $this->node->__isset( 'target' ) ? $this->node->__get( 'target' ) : '' );
}
/**
* Sets a new URL target specific for that category
*
* @param string $value New URL target specific for that category
* @return \Aimeos\MShop\Product\Item\Iface Product item for chaining method calls
*/
public function setTarget( $value )
{
if( (string) $value !== $this->getTarget() ) {
$this->node->__set( 'target', $value );
}
return $this;
}
/**
* Returns the level of the item in the tree
*
* @return integer Level of the item starting with "0" for the root node
*/
public function getLevel()
{
return ( $this->node->__isset( 'level' ) ) ? $this->node->__get( 'level' ) : 0;
}
/**
* Returns the ID of the parent site
*
* @return string Unique ID of the parent site
*/
public function setParentId( $parentid )
{
if( (string) $parentid !== $this->getParentId() ) {
$this->node->__set( 'parentid' );
}
return $this;
}
/**
* Returns the ID of the parent site
*
* @return string Unique ID of the parent site
*/
public function getParentId()
{
return ( $this->node->__isset( 'parentid' ) ) ? $this->node->__get( 'parentid' ) : 0;
}
/**
* Returns the status property of the Site.
*
* @return integer Returns the status of the Site
*/
public function getStatus()
{
return $this->node->getStatus();
}
/**
* Sets status property.
*
* @param integer $status The status of the Site
* @return \Aimeos\MShop\Locale\Item\Site\Iface Locale site item for chaining method calls
*/
public function setStatus( $status )
{
if( (int) $status !== $this->getStatus() )
{
$this->node->setStatus( (int) $status );
}
return $this;
}
/**
* Returns modify date/time of the order item base product.
*
* @return string Returns modify date/time of the order base item
*/
public function getTimeModified()
{
return ( $this->node->__isset( 'mtime' ) ? $this->node->__get( 'mtime' ) : null );
}
/**
* Returns the create date of the item.
*
* @return string ISO date in YYYY-MM-DD hh:mm:ss format
*/
public function getTimeCreated()
{
return ( $this->node->__isset( 'ctime' ) ? $this->node->__get( 'ctime' ) : null );
}
/**
* Returns the editor code of editor who created/modified the item at last.
*
* @return string Editor who created/modified the item at last
*/
public function getEditor()
{
return ( $this->node->__isset( 'editor' ) ? $this->node->__get( 'editor' ) : null );
}
/**
* Returns the item type
*
* @return string Item type, subtypes are separated by slashes
*/
public function getResourceType()
{
return 'locale/site';
}
/**
* Tests if the item is available based on status, time, language and currency
*
* @return boolean True if available, false if not
*/
public function isAvailable()
{
//return parent::isAvailable() && (bool) $this->getStatus();
return (bool) $this->getStatus();
}
/**
* Returns the internal node.
*
* @return \Aimeos\MW\Tree\Node\Iface Internal node object
*/
public function getNode()
{
return $this->node;
}
/**
* Checks, whether this node was modified.
*
* @return boolean True if the content of the node is modified, false if not
*/
public function isModified()
{
return $this->node->isModified();
}
}
Path:ext/myext/Resources/Private/Extensions/myext/lib/custom/src/MShop/Locale/Manager/Site/Nodesites.php
Code: Select all
<?php
/**
* @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
* @copyright Metaways Infosystems GmbH, 2011
* @copyright Aimeos (aimeos.org), 2015-2017
* @package MShop
* @subpackage Locale
*/
namespace Aimeos\MShop\Locale\Manager\Site;
/**
* Default implementation for managing sites.
*
* @package MShop
* @subpackage Locale
*/
class Nodesites
extends Base
//extends Standard
//extends \Aimeos\MShop\Common\Manager\Base
implements \Aimeos\MShop\Locale\Manager\Site\Iface, \Aimeos\MShop\Common\Manager\Factory\Iface
{
private $cache = [];
private $searchConfig = array(
'id' => array(
'code' => 'locale.site.id',
'internalcode' => 'mlocsi."id"',
'internaldeps' => array( 'LEFT JOIN "mshop_locale_site" AS mlocsi ON (mloc."siteid" = mlocsi."id")' ),
'label' => 'Site ID',
'type' => 'string',
'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
'public' => false,
),
'siteid' => array(
'code' => 'locale.site.siteid',
'internalcode' => 'mlocsi."siteid"',
'label' => 'Site ID',
'type' => 'string',
'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
'public' => false,
),
'label' => array(
'code' => 'locale.site.label',
'internalcode' => 'mlocsi."label"',
'label' => 'Site label',
'type' => 'string',
'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
),
'code' => array(
'code' => 'locale.site.code',
'internalcode' => 'mlocsi."code"',
'label' => 'Site code',
'type' => 'string',
'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
),
'locale.site.target' => array(
'code' => 'locale.site.target',
'internalcode' => 'mlocsi."target"',
'label' => 'URL target',
'type' => 'string',
'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
),
'status' => array(
'code' => 'locale.site.status',
'internalcode' => 'mlocsi."status"',
'label' => 'Site status',
'type' => 'integer',
'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
),
'level' => array(
'code' => 'locale.site.level',
'internalcode' => 'mlocsi."level"',
'label' => 'Site tree level',
'type' => 'integer',
'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
'public' => false,
),
'config' => array(
'code' => 'locale.site.config',
'internalcode' => 'mlocsi."config"',
'label' => 'Site config',
'type' => 'string',
'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
'public' => false,
),
'ctime' => array(
'code' => 'locale.site.ctime',
'internalcode' => 'mlocsi."ctime"',
'label' => 'Site create date/time',
'type' => 'datetime',
'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
'public' => false,
),
'mtime' => array(
'code' => 'locale.site.mtime',
'internalcode' => 'mlocsi."mtime"',
'label' => 'Site modify date/time',
'type' => 'datetime',
'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
'public' => false,
),
'editor' => array(
'code' => 'locale.site.editor',
'internalcode' => 'mlocsi."editor"',
'label' => 'Site editor',
'type' => 'string',
'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_STR,
'public' => false,
),
'parentid' => array(
'code' => 'locale.site.parentid',
'internalcode' => 'mlocsi."parentid"',
'label' => 'Site Parent',
'type' => 'integer',
'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
'public' => false,
),
'left' => array(
'code' => 'locale.site.left',
'internalcode' => 'mlocsi."nleft"',
'label' => 'Left value',
'type' => 'integer',
'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
'public' => false,
),
'right' => array(
'code' => 'locale.site.right',
'internalcode' => 'mlocsi."nright"',
'label' => 'Right value',
'type' => 'integer',
'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_INT,
'public' => false,
),
);
/**
* Initializes the object.
*
* @param \Aimeos\MShop\Context\Item\Iface $context Context object
*/
public function __construct( \Aimeos\MShop\Context\Item\Iface $context )
{
parent::__construct( $context, $this->searchConfig );
$this->setResourceName( 'db-locale' );
}
/**
* Removes old entries from the storage.
*
* @param integer[] $siteids List of IDs for sites whose entries should be deleted
*/
public function cleanup( array $siteids )
{
$context = $this->getContext();
$config = $context->getConfig();
/** mshop/locale/manager/site/cleanup/shop/domains
* List of madmin domains names whose items referring to the same site should be deleted as well
*
* As items for each domain can be stored in a separate database, the
* site manager needs a list of domain names used to connect to the
* correct database and to remove all items that belong the the deleted
* site.
*
* For each domain the cleanup will be done by the corresponding MShop
* manager. To keep records for old sites in the database even if the
* site was already deleted, you can configure a new list with the
* domains removed you would like to keep, e.g. the "order" domain to
* keep all orders ever placed.
*
* @param array List of domain names in lower case
* @since 2014.03
* @category Developer
* @see mshop/locale/manager/site/cleanup/admin/domains
*/
$path = 'mshop/locale/manager/site/cleanup/shop/domains';
$default = array(
'attribute', 'catalog', 'coupon', 'customer', 'index',
'media', 'order', 'plugin', 'price', 'product', 'tag',
'service', 'subscription', 'supplier', 'text'
);
foreach( $config->get( $path, $default ) as $domain ) {
\Aimeos\MShop\Factory::createManager( $context, $domain )->cleanup( $siteids );
}
/** mshop/locale/manager/site/cleanup/admin/domains
* List of mshop domains names whose items referring to the same site should be deleted as well
*
* As items for each domain can be stored in a separate database, the
* site manager needs a list of domain names used to connect to the
* correct database and to remove all items that belong the the deleted
* site.
*
* For each domain the cleanup will be done by the corresponding MAdmin
* manager. To keep records for old sites in the database even if the
* site was already deleted, you can configure a new list with the
* domains removed you would like to keep, e.g. the "log" domain to
* keep all log entries ever written.
*
* @param array List of domain names in lower case
* @since 2014.03
* @category Developer
* @see mshop/locale/manager/site/cleanup/shop/domains
*/
$path = 'mshop/locale/manager/site/cleanup/admin/domains';
$default = array( 'job', 'log', 'cache' );
foreach( $config->get( $path, $default ) as $domain ) {
\Aimeos\MAdmin\Factory::createManager( $context, $domain )->cleanup( $siteids );
}
}
/**
* Creates a new site object.
*
* @return \Aimeos\MShop\Locale\Item\Site\Iface
* @throws \Aimeos\MShop\Locale\Exception
*/
public function createItem()
{
//$values = array( 'siteid' => $this->getContext()->getLocale()->getSiteId() );
// Manually setted siteid, cause i want update/edit/create the same tree with nodes for each site
$values = array( 'siteid' => 1);
return $this->createItemBase($values);
}
/**
* Deletes the item specified by its ID.
*
* @param mixed $id ID of the item object
*/
public function deleteItem( $id )
{
//$siteid = $this->getContext()->getLocale()->getSiteId();
$siteid = 1;
$this->begin();
try
{
$this->createTreeManager( $siteid )->deleteNode( $id );
$this->commit();
}
catch( \Exception $e )
{
$this->rollback();
throw $e;
}
}
/**
* Removes multiple items specified by ids in the array.
*
* @param array $ids List of IDs
*/
public function deleteItems( array $ids )
{
foreach( $ids as $id ) {
$this->getObject()->deleteItem( $id );
}
}
/**
* Returns the item specified by its code and domain/type if necessary
*
* @param string $code Code of the item
* @param string[] $ref List of domains to fetch list items and referenced items for
* @param string|null $domain Domain of the item if necessary to identify the item uniquely
* @param string|null $type Type code of the item if necessary to identify the item uniquely
* @param boolean $default True to add default criteria
* @return \Aimeos\MShop\Common\Item\Iface Item object
*/
public function findItem( $code, array $ref = [], $domain = null, $type = null, $default = false )
{
return $this->findItemBase( array( 'locale.site.code' => $code ), $ref, $default );
}
/**
* Returns the site item specified by its ID.
*
* @param string $id Unique ID of the site data in the storage
* @param string[] $ref List of domains to fetch list items and referenced items for
* @param boolean $default Add default criteria
* @return \Aimeos\MShop\Locale\Item\Site\Iface Returns the site item of the given id
* @throws \Aimeos\MShop\Exception If the item couldn't be found
*/
public function getItem( $id, array $ref = [], $default = false )
{
return $this->getItemBase( 'locale.site.id', $id, $ref, $default );
}
/**
* Returns the available manager types
*
* @param boolean $withsub Return also the resource type of sub-managers if true
* @return array Type of the manager and submanagers, subtypes are separated by slashes
*/
public function getResourceType( $withsub = true )
{
$path = 'mshop/locale/manager/site/submanagers';
return $this->getResourceTypeBase( 'locale/site', $path, [], $withsub );
}
/**
* Returns the attributes that can be used for searching.
*
* @param boolean $withsub Return also attributes of sub-managers if true
* @return array List of attribute items implementing \Aimeos\MW\Criteria\Attribute\Iface
*/
public function getSearchAttributes( $withsub = true )
{
/** mshop/locale/manager/site/submanagers
* List of manager names that can be instantiated by the locale site manager
*
* Managers provide a generic interface to the underlying storage.
* Each manager has or can have sub-managers caring about particular
* aspects. Each of these sub-managers can be instantiated by its
* parent manager using the getSubManager() method.
*
* The search keys from sub-managers can be normally used in the
* manager as well. It allows you to search for items of the manager
* using the search keys of the sub-managers to further limit the
* retrieved list of items.
*
* @param array List of sub-manager names
* @since 2014.03
* @category Developer
*/
$path = 'mshop/locale/manager/site/submanagers';
return $this->getSearchAttributesBase( $this->searchConfig, $path, [], $withsub );
}
/**
* Adds a new item object.
*
* @param \Aimeos\MShop\Locale\Item\Site\Iface$item Item which should be inserted
* @param string|null $parentId ID of the parent item where the item should be inserted into
* @param string|null $refId ID of the item where the item should be inserted before (null to append)
* @return \Aimeos\MShop\Locale\Item\Site\Iface $item Updated item including the generated ID
*/
public function insertItem( \Aimeos\MShop\Locale\Item\Site\Iface $item, $parentId = null, $refId = null )
{
//$siteid = $this->getContext()->getLocale()->getSiteId();
$siteid = 1;
$node = $item->getNode();
$this->begin();
try
{
$this->createTreeManager( $siteid )->insertNode( $node, $parentId, $refId );
$this->updateUsage( $node->getId(), $item, true );
$this->commit();
}
catch( \Exception $e )
{
$this->rollback();
throw $e;
}
return $item;
}
/**
* Moves an existing item to the new parent in the storage.
*
* @param integer $id ID of the item that should be moved
* @param integer $oldParentId ID of the old parent item which currently contains the item that should be removed
* @param integer $newParentId ID of the new parent item where the item should be moved to
* @param integer|null $refId ID of the item where the item should be inserted before (null to append)
*/
public function moveItem( $id, $oldParentId, $newParentId, $refId = null )
{
//$siteid = $this->getContext()->getLocale()->getSiteId();
$siteid = 1;
$item = $this->getObject()->getItem( $id );
$this->begin();
try
{
$this->createTreeManager( $siteid )->moveNode( $id, $oldParentId, $newParentId, $refId );
$this->updateUsage( $id, $item );
$this->commit();
}
catch( \Exception $e )
{
$this->rollback();
throw $e;
}
}
/**
* Updates an item object.
*
* @param \Aimeos\MShop\Common\Item\Iface $item Item object whose data should be saved
* @param boolean $fetch True if the new ID should be returned in the item
* @return \Aimeos\MShop\Common\Item\Iface $item Updated item including the generated ID
*/
public function saveItem( \Aimeos\MShop\Common\Item\Iface $item, $fetch = true )
{
$iface = '\\Aimeos\\MShop\\Locale\\Item\\Site\\Iface';
if( !( $item instanceof $iface ) ) {
throw new \Aimeos\MShop\Locale\Exception( sprintf( 'Object is not of required type "%1$s"', $iface ) );
}
if( !$item->isModified() ) {
//return $item;
}
//$siteid = $this->getContext()->getLocale()->getSiteId();
$siteid = 1;
$node = $item->getNode();
$this->begin();
try
{
$this->createTreeManager( $siteid )->saveNode( $node );
$this->updateUsage( $node->getId(), $item );
$this->commit();
}
catch( \Exception $e )
{
$this->rollback();
throw $e;
}
return $item;
}
/**
* Searches for site items matching the given criteria.
*
* @param \Aimeos\MW\Criteria\Iface $search Search criteria object
* @param string[] $ref List of domains to fetch list items and referenced items for
* @param integer|null &$total Number of items that are available in total
* @return array List of site items implementing \Aimeos\MShop\Locale\Item\Site\Iface
*/
public function searchItems( \Aimeos\MW\Criteria\Iface $search, array $ref = [], &$total = null )
{
$items = $nodeMap = $siteMap = [];
$context = $this->getContext();
$dbm = $context->getDatabaseManager();
$dbname = $this->getResourceName();
$conn = $dbm->acquire( $dbname );
try
{
$attributes = $this->getObject()->getSearchAttributes();
$types = $this->getSearchTypes( $attributes );
$translations = $this->getSearchTranslations( $attributes );
$columns = $search->getColumnString( $search->getSortations(), $translations );
$find = array( ':cond', ':order', ':columns', ':start', ':size' );
$replace = array(
$search->getConditionString( $types, $translations ),
$search->getSortationString( $types, $translations ),
( $columns ? ', ' . $columns : '' ),
$search->getSliceStart(),
$search->getSliceSize(),
);
/** mshop/locale/manager/site/standard/search/mysql
* Retrieves the records matched by the given criteria in the database
*
* @see mshop/locale/manager/site/standard/search/ansi
*/
/** mshop/locale/manager/site/standard/search/ansi
* Retrieves the records matched by the given criteria in the database
*
* Fetches the records matched by the given criteria from the attribute
* database. The records must be from one of the sites that are
* configured via the context item. If the current site is part of
* a tree of sites, the SELECT statement can retrieve all records
* from the current site and the complete sub-tree of sites.
*
* As the records can normally be limited by criteria from sub-managers,
* their tables must be joined in the SQL context. This is done by
* using the "internaldeps" property from the definition of the ID
* column of the sub-managers. These internal dependencies specify
* the JOIN between the tables and the used columns for joining. The
* ":joins" placeholder is then replaced by the JOIN strings from
* the sub-managers.
*
* To limit the records matched, conditions can be added to the given
* criteria object. It can contain comparisons like column names that
* must match specific values which can be combined by AND, OR or NOT
* operators. The resulting string of SQL conditions replaces the
* ":cond" placeholder before the statement is sent to the database
* server.
*
* If the records that are retrieved should be ordered by one or more
* columns, the generated string of column / sort direction pairs
* replaces the ":order" placeholder. In case no ordering is required,
* the complete ORDER BY part including the "\/*-orderby*\/...\/*orderby-*\/"
* markers is removed to speed up retrieving the records. Columns of
* sub-managers can also be used for ordering the result set but then
* no index can be used.
*
* The number of returned records can be limited and can start at any
* number between the begining and the end of the result set. For that
* the ":size" and ":start" placeholders are replaced by the
* corresponding values from the criteria object. The default values
* are 0 for the start and 100 for the size value.
*
* The SQL statement should conform to the ANSI standard to be
* compatible with most relational database systems. This also
* includes using double quotes for table and column names.
*
* @param string SQL statement for searching items
* @since 2014.03
* @category Developer
* @see mshop/locale/manager/site/standard/insert/ansi
* @see mshop/locale/manager/site/standard/update/ansi
* @see mshop/locale/manager/site/standard/delete/ansi
* @see mshop/locale/manager/site/standard/count/ansi
* @see mshop/locale/manager/site/standard/newid/ansi
*/
$path = 'mshop/locale/manager/site/standard/search2';
$sql = $this->getSqlConfig( $path );
$results = $this->getSearchResults( $conn, str_replace( $find, $replace, $sql ) );
try
{
while( ( $row = $results->fetch() ) !== false )
{
$config = $row['config'];
if( ( $row['config'] = json_decode( $row['config'], true ) ) === null )
{
$msg = sprintf( 'Invalid JSON as result of search for ID "%2$s" in "%1$s": %3$s', 'mshop_locale.config', $row['id'], $config );
$this->getContext()->getLogger()->log( $msg, \Aimeos\MW\Logger\Base::WARN );
}
$siteMap[$row['id']] = new \Aimeos\MW\Tree\Node\Standard( $row );
//$siteMap[$row['siteid']][$row['id']] = new \Aimeos\MW\Tree\Node\Standard( $row );
}
}
catch( \Exception $e )
{
$results->finish();
throw $e;
}
if( $total !== null ) {
$total = $this->getTotal( $conn, $find, $replace );
}
$dbm->release( $conn, $dbname );
}
catch( \Exception $e )
{
$dbm->release( $conn, $dbname );
throw $e;
}
//return $this->buildItems( $nodeMap, $ref, 'locale.site' );
return $this->buildItems( $siteMap, $ref, 'locale.site' );
}
/**
* Searches for all items matching the given critera.
*
* @param \Aimeos\MW\Criteria\Iface $search Search criteria object
* @param string[] $ref List of domains to fetch list items and referenced items for
* @param integer|null &$total Number of items that are available in total
* @return array List of items implementing \Aimeos\MShop\Common\Item\Iface
*/
// public function searchItems( \Aimeos\MW\Criteria\Iface $search, array $ref = [], &$total = null )
// {
// $nodeMap = $siteMap = [];
// $context = $this->getContext();
// $dbname = $this->getResourceName();
// $dbm = $context->getDatabaseManager();
// $conn = $dbm->acquire( $dbname );
// try
// {
// $required = array( 'locale.site' );
// /** mshop/catalog/manager/sitemode
// * Mode how items from levels below or above in the site tree are handled
// *
// * By default, only items from the current site are fetched from the
// * storage. If the ai-sites extension is installed, you can create a
// * tree of sites. Then, this setting allows you to define for the
// * whole catalog domain if items from parent sites are inherited,
// * sites from child sites are aggregated or both.
// *
// * Available constants for the site mode are:
// * * 0 = only items from the current site
// * * 1 = inherit items from parent sites
// * * 2 = aggregate items from child sites
// * * 3 = inherit and aggregate items at the same time
// *
// * You also need to set the mode in the locale manager
// * (mshop/locale/manager/standard/sitelevel) to one of the constants.
// * If you set it to the same value, it will work as described but you
// * can also use different modes. For example, if inheritance and
// * aggregation is configured the locale manager but only inheritance
// * in the domain manager because aggregating items makes no sense in
// * this domain, then items wil be only inherited. Thus, you have full
// * control over inheritance and aggregation in each domain.
// *
// * @param integer Constant from Aimeos\MShop\Locale\Manager\Base class
// * @category Developer
// * @since 2018.01
// * @see mshop/locale/manager/standard/sitelevel
// */
// $level = \Aimeos\MShop\Locale\Manager\Base::SITE_PATH;
// $level = $context->getConfig()->get( 'mshop/catalog/manager/sitemode', $level );
// /** mshop/catalog/manager/standard/search-item/mysql
// * Retrieves the records matched by the given criteria in the database
// *
// * @see mshop/catalog/manager/standard/search-item/ansi
// */
// /** mshop/catalog/manager/standard/search-item/ansi
// * Retrieves the records matched by the given criteria in the database
// *
// * Fetches the records matched by the given criteria from the catalog
// * database. The records must be from one of the sites that are
// * configured via the context item. If the current site is part of
// * a tree of sites, the SELECT statement can retrieve all records
// * from the current site and the complete sub-tree of sites.
// *
// * As the records can normally be limited by criteria from sub-managers,
// * their tables must be joined in the SQL context. This is done by
// * using the "internaldeps" property from the definition of the ID
// * column of the sub-managers. These internal dependencies specify
// * the JOIN between the tables and the used columns for joining. The
// * ":joins" placeholder is then replaced by the JOIN strings from
// * the sub-managers.
// *
// * To limit the records matched, conditions can be added to the given
// * criteria object. It can contain comparisons like column names that
// * must match specific values which can be combined by AND, OR or NOT
// * operators. The resulting string of SQL conditions replaces the
// * ":cond" placeholder before the statement is sent to the database
// * server.
// *
// * If the records that are retrieved should be ordered by one or more
// * columns, the generated string of column / sort direction pairs
// * replaces the ":order" placeholder. In case no ordering is required,
// * the complete ORDER BY part including the "\/*-orderby*\/...\/*orderby-*\/"
// * markers is removed to speed up retrieving the records. Columns of
// * sub-managers can also be used for ordering the result set but then
// * no index can be used.
// *
// * The number of returned records can be limited and can start at any
// * number between the begining and the end of the result set. For that
// * the ":size" and ":start" placeholders are replaced by the
// * corresponding values from the criteria object. The default values
// * are 0 for the start and 100 for the size value.
// *
// * The SQL statement should conform to the ANSI standard to be
// * compatible with most relational database systems. This also
// * includes using double quotes for table and column names.
// *
// * @param string SQL statement for searching items
// * @since 2014.03
// * @category Developer
// * @see mshop/catalog/manager/standard/delete/ansi
// * @see mshop/catalog/manager/standard/get/ansi
// * @see mshop/catalog/manager/standard/insert/ansi
// * @see mshop/catalog/manager/standard/update/ansi
// * @see mshop/catalog/manager/standard/newid/ansi
// * @see mshop/catalog/manager/standard/search/ansi
// * @see mshop/catalog/manager/standard/count/ansi
// * @see mshop/catalog/manager/standard/move-left/ansi
// * @see mshop/catalog/manager/standard/move-right/ansi
// * @see mshop/catalog/manager/standard/update-parentid/ansi
// */
// $cfgPathSearch = 'mshop/locale/manager/site/standard/search-item';
// /** mshop/catalog/manager/standard/count/mysql
// * Counts the number of records matched by the given criteria in the database
// *
// * @see mshop/catalog/manager/standard/count/ansi
// */
// /** mshop/catalog/manager/standard/count/ansi
// * Counts the number of records matched by the given criteria in the database
// *
// * Counts all records matched by the given criteria from the catalog
// * database. The records must be from one of the sites that are
// * configured via the context item. If the current site is part of
// * a tree of sites, the statement can count all records from the
// * current site and the complete sub-tree of sites.
// *
// * As the records can normally be limited by criteria from sub-managers,
// * their tables must be joined in the SQL context. This is done by
// * using the "internaldeps" property from the definition of the ID
// * column of the sub-managers. These internal dependencies specify
// * the JOIN between the tables and the used columns for joining. The
// * ":joins" placeholder is then replaced by the JOIN strings from
// * the sub-managers.
// *
// * To limit the records matched, conditions can be added to the given
// * criteria object. It can contain comparisons like column names that
// * must match specific values which can be combined by AND, OR or NOT
// * operators. The resulting string of SQL conditions replaces the
// * ":cond" placeholder before the statement is sent to the database
// * server.
// *
// * Both, the strings for ":joins" and for ":cond" are the same as for
// * the "search" SQL statement.
// *
// * Contrary to the "search" statement, it doesn't return any records
// * but instead the number of records that have been found. As counting
// * thousands of records can be a long running task, the maximum number
// * of counted records is limited for performance reasons.
// *
// * The SQL statement should conform to the ANSI standard to be
// * compatible with most relational database systems. This also
// * includes using double quotes for table and column names.
// *
// * @param string SQL statement for counting items
// * @since 2014.03
// * @category Developer
// * @see mshop/catalog/manager/standard/delete/ansi
// * @see mshop/catalog/manager/standard/get/ansi
// * @see mshop/catalog/manager/standard/insert/ansi
// * @see mshop/catalog/manager/standard/update/ansi
// * @see mshop/catalog/manager/standard/newid/ansi
// * @see mshop/catalog/manager/standard/search/ansi
// * @see mshop/catalog/manager/standard/search-item/ansi
// * @see mshop/catalog/manager/standard/move-left/ansi
// * @see mshop/catalog/manager/standard/move-right/ansi
// * @see mshop/catalog/manager/standard/update-parentid/ansi
// */
// $cfgPathCount = 'mshop/locale/manager/site/standard/count-items';
// if( $search->getSortations() === [] ) {
// $search->setSortations( [$search->sort( '+', 'locale.site.left')] );
// }
// $results = $this->searchItemsBase( $conn, $search, $cfgPathSearch, $cfgPathCount, $required, $total, $level );
// while( ( $row = $results->fetch() ) !== false ) {
// //$siteMap[$row['siteid']][$row['id']] = new \Aimeos\MW\Tree\Node\Standard( $row );
// $siteMap[$row['id']] = new \Aimeos\MW\Tree\Node\Standard( $row );
// }
// // if( $total !== null ) {
// // $find = array( ':cond', ':order', ':columns', ':start', ':size' );
// // $replace = array(
// // $search->getConditionString( $types, $translations ),
// // $search->getSortationString( $types, $translations ),
// // ( $columns ? ', ' . $columns : '' ),
// // $search->getSliceStart(),
// // $search->getSliceSize(),
// // );
// // $total = $this->getTotal( $conn, $find, $replace );
// // }
// $dbm->release( $conn, $dbname );
// }
// catch( \Exception $e )
// {
// $dbm->release( $conn, $dbname );
// throw $e;
// }
// return $this->buildItems( $siteMap, $ref, 'locale.site' );
// /**
// *
// * Probleme with this search
// *
// * Oops, an error occurred!
// * SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias: 'mlocsi'
// *
// */
// }
/**
* Returns a list of item IDs, that are in the path of given item ID.
*
* @param integer $id ID of item to get the path for
* @param array $ref List of domains to fetch list items and referenced items for
* @return \Aimeos\MShop\Locale\Item\Site\Iface[] Associative list of items implementing \Aimeos\MShop\Locale\Item\Site\Iface with IDs as keys
*/
public function getPath( $id, array $ref = [] )
{
//$sitePath = array_reverse( $this->getContext()->getLocale()->getSitePath() );
$sitePath = array( 'siteid' => 1);
foreach( $sitePath as $siteId )
{
try {
$path = $this->createTreeManager( $siteId )->getPath( $id );
} catch( \Exception $e ) {
continue;
}
if( !empty( $path ) )
{
$itemMap = [];
foreach( $path as $node ) {
$itemMap[$node->getId()] = $node;
}
return $this->buildItems( $itemMap, $ref, 'locale.site' );
}
}
throw new \Aimeos\MShop\Locale\Exception( sprintf( 'Locale path for ID "%1$s" not found', $id ) );
}
/**
* Returns a node and its descendants depending on the given resource.
*
* @param integer|null $id Retrieve nodes starting from the given ID
* @param array List of domains (e.g. text, media, etc.) whose referenced items should be attached to the objects
* @param integer $level One of the level constants from \Aimeos\MW\Tree\Manager\Base
* @return \Aimeos\MShop\Locale\Item\Site\Iface Site item
*/
public function getTree( $id = null, array $ref = [], $level = \Aimeos\MW\Tree\Manager\Base::LEVEL_TREE )
{
//$sitePath = array_reverse( $this->getContext()->getLocale()->getSitePath() );
$sitePath = array( 'siteid' => 1);
foreach( $sitePath as $siteId )
{
try {
$node = $this->createTreeManager( $siteId )->getNode( $id, $level, $criteria );
} catch( \Exception $e ) {
continue;
}
//$nodeMap = $this->getNodeMap( $node );
$nodeMap = $this->getNodeMap( $node );
$nodeid = $node->getId();
$item = $this->createItemBase( [], [], $node );
$this->createTree( $node, $item );
if( $id !== null )
{
$itemid = $item->getId();
if( !isset( $this->cache[$id] ) ) {
$this->cache[$id] = $item;;
}
return $this->cache[$id];
}
$this->cache[$item->getId()] = $item;
return $item;
}
throw new \Aimeos\MShop\Locale\Exception( sprintf( 'No Locale node for ID "%1$s"', $id ) );
}
/**
* Returns a new sub manager of the given type and name.
*
* @param string $manager Name of the sub manager type in lower case
* @param string|null $name Name of the implementation, will be from configuration (or Default) if null
* @return \Aimeos\MShop\Locale\Manager\Iface manager
*/
public function getSubManager( $manager, $name = null )
{
/** mshop/locale/manager/site/name
* Class name of the used locale site manager implementation
*
* Each default locale site manager can be replaced by an alternative imlementation.
* To use this implementation, you have to set the last part of the class
* name as configuration value so the manager factory knows which class it
* has to instantiate.
*
* For example, if the name of the default class is
*
* \Aimeos\MShop\Locale\Manager\Site\Standard
*
* and you want to replace it with your own version named
*
* \Aimeos\MShop\Locale\Manager\Site\Mysite
*
* then you have to set the this configuration option:
*
* mshop/locale/manager/site/name = Mysite
*
* The value is the last part of your own class name and it's case sensitive,
* so take care that the configuration value is exactly named like the last
* part of the class name.
*
* The allowed characters of the class name are A-Z, a-z and 0-9. No other
* characters are possible! You should always start the last part of the class
* name with an upper case character and continue only with lower case characters
* or numbers. Avoid chamel case names like "MySite"!
*
* @param string Last part of the class name
* @since 2014.03
* @category Developer
*/
/** mshop/locale/manager/site/decorators/excludes
* Excludes decorators added by the "common" option from the locale site manager
*
* Decorators extend the functionality of a class by adding new aspects
* (e.g. log what is currently done), executing the methods of the underlying
* class only in certain conditions (e.g. only for logged in users) or
* modify what is returned to the caller.
*
* This option allows you to remove a decorator added via
* "mshop/common/manager/decorators/default" before they are wrapped
* around the locale site manager.
*
* mshop/locale/manager/site/decorators/excludes = array( 'decorator1' )
*
* This would remove the decorator named "decorator1" from the list of
* common decorators ("\Aimeos\MShop\Common\Manager\Decorator\*") added via
* "mshop/common/manager/decorators/default" for the locale site manager.
*
* @param array List of decorator names
* @since 2014.03
* @category Developer
* @see mshop/common/manager/decorators/default
* @see mshop/locale/manager/site/decorators/global
* @see mshop/locale/manager/site/decorators/local
*/
/** mshop/locale/manager/site/decorators/global
* Adds a list of globally available decorators only to the locale site manager
*
* Decorators extend the functionality of a class by adding new aspects
* (e.g. log what is currently done), executing the methods of the underlying
* class only in certain conditions (e.g. only for logged in users) or
* modify what is returned to the caller.
*
* This option allows you to wrap global decorators
* ("\Aimeos\MShop\Common\Manager\Decorator\*") around the locale site
* manager.
*
* mshop/locale/manager/site/decorators/global = array( 'decorator1' )
*
* This would add the decorator named "decorator1" defined by
* "\Aimeos\MShop\Common\Manager\Decorator\Decorator1" only to the locale
* site manager.
*
* @param array List of decorator names
* @since 2014.03
* @category Developer
* @see mshop/common/manager/decorators/default
* @see mshop/locale/manager/site/decorators/excludes
* @see mshop/locale/manager/site/decorators/local
*/
/** mshop/locale/manager/site/decorators/local
* Adds a list of local decorators only to the locale site manager
*
* Decorators extend the functionality of a class by adding new aspects
* (e.g. log what is currently done), executing the methods of the underlying
* class only in certain conditions (e.g. only for logged in users) or
* modify what is returned to the caller.
*
* This option allows you to wrap local decorators
* ("\Aimeos\MShop\Locale\Manager\Site\Decorator\*") around the locale site
* manager.
*
* mshop/locale/manager/site/decorators/local = array( 'decorator2' )
*
* This would add the decorator named "decorator2" defined by
* "\Aimeos\MShop\Locale\Manager\Site\Decorator\Decorator2" only to the
* locale site manager.
*
* @param array List of decorator names
* @since 2014.03
* @category Developer
* @see mshop/common/manager/decorators/default
* @see mshop/locale/manager/site/decorators/excludes
* @see mshop/locale/manager/site/decorators/global
*/
return $this->getSubManagerBase( 'locale', 'site/' . $manager, $name );
}
/**
* Updates the usage information of a node.
*
* @param integer $id Id of the record
* @param \Aimeos\MShop\Locale\Item\Site\Iface $item Catalog item
* @param boolean $case True if the record shoud be added or false for an update
*
*/
private function updateUsage( $id, \Aimeos\MShop\Locale\Item\Site\Iface $item, $case = false )
{
$date = date( 'Y-m-d H:i:s' );
$context = $this->getContext();
$dbm = $context->getDatabaseManager();
$dbname = $this->getResourceName();
$conn = $dbm->acquire( $dbname );
try
{
//$siteid = $context->getLocale()->getSiteId();
$siteid = 1;
if( $case !== true )
{
/** mshop/catalog/manager/standard/update-usage/mysql
* Updates the config, editor and mtime value of an updated record
*
* @see mshop/catalog/manager/standard/update-usage/ansi
*/
/** mshop/catalog/manager/standard/update-usage/ansi
* Updates the config, editor and mtime value of an updated record
*
* Each record contains some usage information like when it was
* created, last modified and by whom. These information are part
* of the catalog items and the generic tree manager doesn't care
* about this information. Thus, they are updated after the tree
* manager saved the basic record information.
*
* The SQL statement must be a string suitable for being used as
* prepared statement. It must include question marks for binding
* the values from the catalog item to the statement before they are
* sent to the database server. The order of the columns must
* correspond to the order in the method using this statement,
* so the correct values are bound to the columns.
*
* The SQL statement should conform to the ANSI standard to be
* compatible with most relational database systems. This also
* includes using double quotes for table and column names.
*
* @param string SQL statement for updating records
* @since 2014.03
* @category Developer
* @see mshop/catalog/manager/standard/delete/ansi
* @see mshop/catalog/manager/standard/get/ansi
* @see mshop/catalog/manager/standard/insert/ansi
* @see mshop/catalog/manager/standard/newid/ansi
* @see mshop/catalog/manager/standard/search/ansi
* @see mshop/catalog/manager/standard/search-item/ansi
* @see mshop/catalog/manager/standard/count/ansi
* @see mshop/catalog/manager/standard/move-left/ansi
* @see mshop/catalog/manager/standard/move-right/ansi
* @see mshop/catalog/manager/standard/update-parentid/ansi
* @see mshop/catalog/manager/standard/insert-usage/ansi
*/
$path = 'mshop/locale/manager/site/standard/update-usage';
}
else
{
/** mshop/catalog/manager/standard/insert-usage/mysql
* Updates the config, editor, ctime and mtime value of an inserted record
*
* @see mshop/catalog/manager/standard/insert-usage/ansi
*/
/** mshop/catalog/manager/standard/insert-usage/ansi
* Updates the config, editor, ctime and mtime value of an inserted record
*
* Each record contains some usage information like when it was
* created, last modified and by whom. These information are part
* of the catalog items and the generic tree manager doesn't care
* about this information. Thus, they are updated after the tree
* manager inserted the basic record information.
*
* The SQL statement must be a string suitable for being used as
* prepared statement. It must include question marks for binding
* the values from the catalog item to the statement before they are
* sent to the database server. The order of the columns must
* correspond to the order in the method using this statement,
* so the correct values are bound to the columns.
*
* The SQL statement should conform to the ANSI standard to be
* compatible with most relational database systems. This also
* includes using double quotes for table and column names.
*
* @param string SQL statement for updating records
* @since 2014.03
* @category Developer
* @see mshop/catalog/manager/standard/delete/ansi
* @see mshop/catalog/manager/standard/get/ansi
* @see mshop/catalog/manager/standard/insert/ansi
* @see mshop/catalog/manager/standard/newid/ansi
* @see mshop/catalog/manager/standard/search/ansi
* @see mshop/catalog/manager/standard/search-item/ansi
* @see mshop/catalog/manager/standard/count/ansi
* @see mshop/catalog/manager/standard/move-left/ansi
* @see mshop/catalog/manager/standard/move-right/ansi
* @see mshop/catalog/manager/standard/update-parentid/ansi
* @see mshop/catalog/manager/standard/update-usage/ansi
*/
$path = 'mshop/locale/manager/site/standard/insert-usage';
}
$stmt = $conn->create( $this->getSqlConfig( $path ) );
$stmt->bind( 1, json_encode( $item->getConfig() ) );
$stmt->bind( 2, $date ); // mtime
$stmt->bind( 3, $context->getEditor() );
$stmt->bind( 4, $item->getTarget() );
if( $case !== true )
{
$stmt->bind( 5, $siteid, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
$stmt->bind( 6, $id, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
}
else
{
$stmt->bind( 5, $date ); // ctime
$stmt->bind( 6, $siteid, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
$stmt->bind( 7, $id, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
}
$stmt->execute()->finish();
$dbm->release( $conn, $dbname );
}
catch( \Exception $e )
{
$dbm->release( $conn, $dbname );
throw $e;
}
}
/**
* Creates a search object and sets base criteria.
*
* @param boolean $default
* @return \Aimeos\MW\Criteria\Iface
*/
public function createSearch( $default = false )
{
if( $default === true ) {
$search = $this->createSearchBase( 'locale.site' );
} else {
$search = parent::createSearch( $default );
}
$expr = array(
//$search->compare( '==', 'locale.site.level', 0 ),
$search->getConditions(),
);
$search->setConditions( $search->combine( '&&', $expr ) );
return $search;
}
/**
* Returns the search results for the given SQL statement.
*
* @param \Aimeos\MW\DB\Connection\Iface $conn Database connection
* @param $sql SQL statement
* @return \Aimeos\MW\DB\Result\Iface Search result object
*/
protected function getSearchResults( \Aimeos\MW\DB\Connection\Iface $conn, $sql )
{
$statement = $conn->create( $sql );
$level = \Aimeos\MW\Logger\Base::DEBUG;
$this->getContext()->getLogger()->log( __METHOD__ . ': SQL statement: ' . $statement, $level, 'core/sql' );
$results = $statement->execute();
return $results;
}
/**
* Returns the raw search config array.
*
* @return array List of search config arrays
*/
protected function getSearchConfig()
{
return $this->searchConfig;
}
/**
* Returns the total number of items found for the conditions
*
* @param \Aimeos\MW\DB\Connection\Iface $conn Database connection
* @param array $find List of markers that should be replaced in the SQL statement
* @param array $replace List of replacements for the markers in the SQL statement
* @throws \Aimeos\MShop\Locale\Exception If no total value was found
* @return integer Total number of found items
*/
protected function getTotal( \Aimeos\MW\DB\Connection\Iface $conn, array $find, array $replace )
{
/** mshop/locale/manager/site/standard/count/mysql
* Counts the number of records matched by the given criteria in the database
*
* @see mshop/locale/manager/site/standard/count/ansi
*/
/** mshop/locale/manager/site/standard/count/ansi
* Counts the number of records matched by the given criteria in the database
*
* Counts all records matched by the given criteria from the attribute
* database. The records must be from one of the sites that are
* configured via the context item. If the current site is part of
* a tree of sites, the statement can count all records from the
* current site and the complete sub-tree of sites.
*
* As the records can normally be limited by criteria from sub-managers,
* their tables must be joined in the SQL context. This is done by
* using the "internaldeps" property from the definition of the ID
* column of the sub-managers. These internal dependencies specify
* the JOIN between the tables and the used columns for joining. The
* ":joins" placeholder is then replaced by the JOIN strings from
* the sub-managers.
*
* To limit the records matched, conditions can be added to the given
* criteria object. It can contain comparisons like column names that
* must match specific values which can be combined by AND, OR or NOT
* operators. The resulting string of SQL conditions replaces the
* ":cond" placeholder before the statement is sent to the database
* server.
*
* Both, the strings for ":joins" and for ":cond" are the same as for
* the "search" SQL statement.
*
* Contrary to the "search" statement, it doesn't return any records
* but instead the number of records that have been found. As counting
* thousands of records can be a long running task, the maximum number
* of counted records is limited for performance reasons.
*
* The SQL statement should conform to the ANSI standard to be
* compatible with most relational database systems. This also
* includes using double quotes for table and column names.
*
* @param string SQL statement for counting items
* @since 2014.03
* @category Developer
* @see mshop/locale/manager/site/standard/insert/ansi
* @see mshop/locale/manager/site/standard/update/ansi
* @see mshop/locale/manager/site/standard/delete/ansi
* @see mshop/locale/manager/site/standard/search/ansi
* @see mshop/locale/manager/site/standard/newid/ansi
*/
$path = 'mshop/locale/manager/site/standard/count';
$sql = $this->getSqlConfig( $path );
$results = $this->getSearchResults( $conn, str_replace( $find, $replace, $sql ) );
$row = $results->fetch();
$results->finish();
if( $row === false ) {
throw new \Aimeos\MShop\Locale\Exception( 'No total results value found' );
}
return $row['count'];
}
}
Last edited by tenkraD on 05 Dec 2018, 14:50, edited 3 times in total.
Re: Multiple Site 1 Basket / Checkout
< Part 2 >
Base Manager
Path: /ext/myext/Resources/Private/Extensions/myext/lib/custom/src/MShop/Locale/Manager/Site/Base.php
Database Table Setup
Configuration for Manager and Item - mshop.php
Base Manager
Path: /ext/myext/Resources/Private/Extensions/myext/lib/custom/src/MShop/Locale/Manager/Site/Base.php
Code: Select all
<?php
/**
* @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
* @copyright Metaways Infosystems GmbH, 2011
* @copyright Aimeos (aimeos.org), 2015-2017
* @package MShop
* @subpackage Locale
*/
namespace Aimeos\MShop\Locale\Manager\Site;
/**
* Catalog manager with methods for managing categories products, text, media.
*
* @package MShop
* @subpackage Catalog
*/
abstract class Base
extends \Aimeos\MShop\Common\Manager\Base
{
private $searchConfig;
private $filter = [];
private $treeManagers = [];
/**
* Initializes the object.
*
* @param \Aimeos\MShop\Context\Item\Iface $context Context object
*/
public function __construct( \Aimeos\MShop\Context\Item\Iface $context, array $searchConfig )
{
parent::__construct( $context );
$this->searchConfig = $searchConfig;
}
/**
* Registers a new item filter for the given name
*
* To prevent catalog items to be added to the tree, you can register a
* closure function that checks if the item should be part of the category
* tree or not. The function signature must be:
*
* function( \Aimeos\MShop\Common\Item\ListRef\Iface $item, $index )
*
* It must accept an item implementing the list reference interface and the
* index of the category in the list starting from 0. Its return value must
* be a boolean value of "true" if the category item should be added to the
* tree and "false" if not.
*
* @param string $name Filter name
* @param \Closure $fcn Callback function
*/
public function registerItemFilter( $name, \Closure $fcn )
{
$this->filter[$name] = $fcn;
}
/**
* Creates the catalog item objects.
*
* @param array $itemMap Associative list of catalog ID / tree node pairs
* @param array $domains List of domains (e.g. text, media) whose items should be attached to the catalog items
* @param string $prefix Domain prefix
* @param array $local Associative list of IDs as keys and the associative array of items as values
* @param array $local2 Associative list of IDs as keys and the associative array of items as values
* @return array List of items implementing \Aimeos\MShop\Catalog\Item\Iface
*/
protected function buildItems( array $itemMap, $domains, $prefix, array $local = [], array $local2 = [] )
{
$items = [];
foreach( $itemMap as $id => $node )
{
$items[$id] = $this->createItemBase( [], [], $node );
}
return $items;
}
/**
* Creates a new catalog item.
*
* @param array $values Associative list of key/value pairs
* @param array $children List of tree nodes implementing \Aimeos\MW\Tree\Node\Iface
* @param \Aimeos\MW\Tree\Node\Iface|null $node Tree node object
* @return \Aimeos\MShop\Catalog\Item\Iface New catalog item
*/
protected function createItemBase( array $values = [], array $children = [], \Aimeos\MW\Tree\Node\Iface $node = null )
{
if( $node === null )
{
if( !isset( $values['siteid'] ) ) {
throw new \Aimeos\MShop\Locale\Manager\Site\Exception( 'No site ID available for creating a Locale item' );
}
$node = $this->createTreeManager( $values['siteid'] )->createNode();
$node->siteid = $values['siteid'];
}
// if( isset( $node->config ) && ( $result = json_decode( $node->config, true ) ) !== null ) {
// $node->config = $result;
// }
return new \Aimeos\MShop\Locale\Item\Site\Nodesites( $node, $children );
}
/**
* Builds the tree of catalog items.
*
* @param \Aimeos\MW\Tree\Node\Iface $node Parent tree node
* @param \Aimeos\MShop\Catalog\Item\Iface $item Parent tree catalog Item
* @param array $listItemMap Associative list of parent-item-ID / list items for the catalog item
* @param array $refItemMap Associative list of parent-item-ID/domain/items key/value pairs
*/
protected function createTree( \Aimeos\MW\Tree\Node\Iface $node, \Aimeos\MShop\Locale\Item\Site\Iface $item, array $listItems = [], array $refItems = [] )
{
foreach( $node->getChildren() as $idx => $child )
{
$newItem = $this->createItemBase( [], [], $child );
$result = true;
foreach( $this->filter as $fcn ) {
$result = $result && $fcn( $newItem, $idx );
}
if( $result === true )
{
$item->addChild( $newItem );
$this->createTree( $child, $newItem );
}
}
}
/**
* Creates an object for managing the nested set.
*
* @param integer $siteid Site ID for the specific tree
* @return \Aimeos\MW\Tree\Manager\Iface Tree manager
*/
protected function createTreeManager( $siteid )
{
if( !isset( $this->treeManagers[$siteid] ) )
{
$context = $this->getContext();
$dbm = $context->getDatabaseManager();
$treeConfig = array(
'search' => $this->searchConfig,
'dbname' => $this->getResourceName(),
'sql' => array(
/** mshop/locale/manager/site/standard/delete/mysql
* Deletes the items matched by the given IDs from the database
*
* @see mshop/locale/manager/site/standard/delete/ansi
*/
/** mshop/locale/manager/site/standard/delete/ansi
* Deletes the items matched by the given IDs from the database
*
* Removes the records specified by the given IDs from the database.
* The records must be from the site that is configured via the
* context item.
*
* The ":cond" placeholder is replaced by the name of the ID column and
* the given ID or list of IDs while the site ID is bound to the question
* mark.
*
* The SQL statement should conform to the ANSI standard to be
* compatible with most relational database systems. This also
* includes using double quotes for table and column names.
*
* @param string SQL statement for deleting items
* @since 2014.03
* @category Developer
* @see mshop/locale/manager/site/standard/get/ansi
* @see mshop/locale/manager/site/standard/insert/ansi
* @see mshop/locale/manager/site/standard/update/ansi
* @see mshop/locale/manager/site/standard/newid/ansi
* @see mshop/locale/manager/site/standard/search/ansi
* @see mshop/locale/manager/site/standard/search-item/ansi
* @see mshop/locale/manager/site/standard/count/ansi
* @see mshop/locale/manager/site/standard/move-left/ansi
* @see mshop/locale/manager/site/standard/move-right/ansi
* @see mshop/locale/manager/site/standard/update-parentid/ansi
* @see mshop/locale/manager/site/standard/insert-usage/ansi
* @see mshop/locale/manager/site/standard/update-usage/ansi
*/
'delete' => str_replace( ':siteid', $siteid, $this->getSqlConfig( 'mshop/locale/manager/site/standard/delete' ) ),
/** mshop/locale/manager/site/standard/get/mysql
* Returns a node record and its complete subtree optionally limited by the level
*
* @see mshop/locale/manager/site/standard/get/ansi
*/
/** mshop/locale/manager/site/standard/get/ansi
* Returns a node record and its complete subtree optionally limited by the level
*
* Fetches the records matched by the given criteria from the catalog
* database. The records must be from one of the sites that are
* configured via the context item. If the current site is part of
* a tree of sites, the SELECT statement can retrieve all records
* from the current site and the complete sub-tree of sites. This
* statement retrieves all records that are part of the subtree for
* the found node. The depth can be limited by the "level" number.
*
* To limit the records matched, conditions can be added to the given
* criteria object. It can contain comparisons like column names that
* must match specific values which can be combined by AND, OR or NOT
* operators. The resulting string of SQL conditions replaces the
* ":cond" placeholder before the statement is sent to the database
* server.
*
* The SQL statement should conform to the ANSI standard to be
* compatible with most relational database systems. This also
* includes using double quotes for table and column names.
*
* @param string SQL statement for searching items
* @since 2014.03
* @category Developer
* @see mshop/locale/manager/site/standard/delete/ansi
* @see mshop/locale/manager/site/standard/insert/ansi
* @see mshop/locale/manager/site/standard/update/ansi
* @see mshop/locale/manager/site/standard/newid/ansi
* @see mshop/locale/manager/site/standard/search/ansi
* @see mshop/locale/manager/site/standard/search-item/ansi
* @see mshop/locale/manager/site/standard/count/ansi
* @see mshop/locale/manager/site/standard/move-left/ansi
* @see mshop/locale/manager/site/standard/move-right/ansi
* @see mshop/locale/manager/site/standard/update-parentid/ansi
* @see mshop/locale/manager/site/standard/insert-usage/ansi
* @see mshop/locale/manager/site/standard/update-usage/ansi
*/
'get' => str_replace( ':siteid', $siteid, $this->getSqlConfig( 'mshop/locale/manager/site/standard/get' ) ),
/** mshop/locale/manager/site/standard/insert/mysql
* Inserts a new catalog node into the database table
*
* @see mshop/locale/manager/site/standard/insert/ansi
*/
/** mshop/locale/manager/site/standard/insert/ansi
* Inserts a new catalog node into the database table
*
* Items with no ID yet (i.e. the ID is NULL) will be created in
* the database and the newly created ID retrieved afterwards
* using the "newid" SQL statement.
*
* The SQL statement must be a string suitable for being used as
* prepared statement. It must include question marks for binding
* the values from the catalog item to the statement before they are
* sent to the database server. The number of question marks must
* be the same as the number of columns listed in the INSERT
* statement. The order of the columns must correspond to the
* order in the insertNode() method, so the correct values are
* bound to the columns.
*
* The SQL statement should conform to the ANSI standard to be
* compatible with most relational database systems. This also
* includes using double quotes for table and column names.
*
* @param string SQL statement for inserting records
* @since 2014.03
* @category Developer
* @see mshop/locale/manager/site/standard/delete/ansi
* @see mshop/locale/manager/site/standard/get/ansi
* @see mshop/locale/manager/site/standard/update/ansi
* @see mshop/locale/manager/site/standard/newid/ansi
* @see mshop/locale/manager/site/standard/search/ansi
* @see mshop/locale/manager/site/standard/search-item/ansi
* @see mshop/locale/manager/site/standard/count/ansi
* @see mshop/locale/manager/site/standard/move-left/ansi
* @see mshop/locale/manager/site/standard/move-right/ansi
* @see mshop/locale/manager/site/standard/update-parentid/ansi
* @see mshop/locale/manager/site/standard/insert-usage/ansi
* @see mshop/locale/manager/site/standard/update-usage/ansi
*/
'insert' => str_replace( ':siteid', $siteid, $this->getSqlConfig( 'mshop/locale/manager/site/standard/insert' ) ),
/** mshop/locale/manager/site/standard/move-left/mysql
* Updates the left values of the nodes that are moved within the catalog tree
*
* @see mshop/locale/manager/site/standard/move-left/ansi
*/
/** mshop/locale/manager/site/standard/move-left/ansi
* Updates the left values of the nodes that are moved within the catalog tree
*
* When moving nodes or subtrees with the catalog tree, the left
* value of each moved node inside the nested set must be updated
* to match their new position within the catalog tree.
*
* The SQL statement must be a string suitable for being used as
* prepared statement. It must include question marks for binding
* the values from the catalog item to the statement before they are
* sent to the database server. The order of the columns must
* correspond to the order in the moveNode() method, so the
* correct values are bound to the columns.
*
* The SQL statement should conform to the ANSI standard to be
* compatible with most relational database systems. This also
* includes using double quotes for table and column names.
*
* @param string SQL statement for updating records
* @since 2014.03
* @category Developer
* @see mshop/locale/manager/site/standard/delete/ansi
* @see mshop/locale/manager/site/standard/get/ansi
* @see mshop/locale/manager/site/standard/insert/ansi
* @see mshop/locale/manager/site/standard/update/ansi
* @see mshop/locale/manager/site/standard/newid/ansi
* @see mshop/locale/manager/site/standard/search/ansi
* @see mshop/locale/manager/site/standard/search-item/ansi
* @see mshop/locale/manager/site/standard/count/ansi
* @see mshop/locale/manager/site/standard/move-right/ansi
* @see mshop/locale/manager/site/standard/update-parentid/ansi
* @see mshop/locale/manager/site/standard/insert-usage/ansi
* @see mshop/locale/manager/site/standard/update-usage/ansi
*/
'move-left' => str_replace( ':siteid', $siteid, $this->getSqlConfig( 'mshop/locale/manager/site/standard/move-left' ) ),
/** mshop/locale/manager/site/standard/move-right/mysql
* Updates the left values of the nodes that are moved within the catalog tree
*
* @see mshop/locale/manager/site/standard/move-right/ansi
*/
/** mshop/locale/manager/site/standard/move-right/ansi
* Updates the left values of the nodes that are moved within the catalog tree
*
* When moving nodes or subtrees with the catalog tree, the right
* value of each moved node inside the nested set must be updated
* to match their new position within the catalog tree.
*
* The SQL statement must be a string suitable for being used as
* prepared statement. It must include question marks for binding
* the values from the catalog item to the statement before they are
* sent to the database server. The order of the columns must
* correspond to the order in the moveNode() method, so the
* correct values are bound to the columns.
*
* The SQL statement should conform to the ANSI standard to be
* compatible with most relational database systems. This also
* includes using double quotes for table and column names.
*
* @param string SQL statement for updating records
* @since 2014.03
* @category Developer
* @see mshop/locale/manager/site/standard/delete/ansi
* @see mshop/locale/manager/site/standard/get/ansi
* @see mshop/locale/manager/site/standard/insert/ansi
* @see mshop/locale/manager/site/standard/update/ansi
* @see mshop/locale/manager/site/standard/newid/ansi
* @see mshop/locale/manager/site/standard/search/ansi
* @see mshop/locale/manager/site/standard/search-item/ansi
* @see mshop/locale/manager/site/standard/count/ansi
* @see mshop/locale/manager/site/standard/move-left/ansi
* @see mshop/locale/manager/site/standard/update-parentid/ansi
* @see mshop/locale/manager/site/standard/insert-usage/ansi
* @see mshop/locale/manager/site/standard/update-usage/ansi
*/
'move-right' => str_replace( ':siteid', $siteid, $this->getSqlConfig( 'mshop/locale/manager/site/standard/move-right' ) ),
/** mshop/locale/manager/site/standard/search/mysql
* Retrieves the records matched by the given criteria in the database
*
* @see mshop/locale/manager/site/standard/search/ansi
*/
/** mshop/locale/manager/site/standard/search/ansi
* Retrieves the records matched by the given criteria in the database
*
* Fetches the records matched by the given criteria from the catalog
* database. The records must be from one of the sites that are
* configured via the context item. If the current site is part of
* a tree of sites, the SELECT statement can retrieve all records
* from the current site and the complete sub-tree of sites.
*
* To limit the records matched, conditions can be added to the given
* criteria object. It can contain comparisons like column names that
* must match specific values which can be combined by AND, OR or NOT
* operators. The resulting string of SQL conditions replaces the
* ":cond" placeholder before the statement is sent to the database
* server.
*
* If the records that are retrieved should be ordered by one or more
* columns, the generated string of column / sort direction pairs
* replaces the ":order" placeholder.
*
* The SQL statement should conform to the ANSI standard to be
* compatible with most relational database systems. This also
* includes using double quotes for table and column names.
*
* @param string SQL statement for searching items
* @since 2014.03
* @category Developer
* @see mshop/locale/manager/site/standard/delete/ansi
* @see mshop/locale/manager/site/standard/get/ansi
* @see mshop/locale/manager/site/standard/insert/ansi
* @see mshop/locale/manager/site/standard/update/ansi
* @see mshop/locale/manager/site/standard/newid/ansi
* @see mshop/locale/manager/site/standard/search-item/ansi
* @see mshop/locale/manager/site/standard/count/ansi
* @see mshop/locale/manager/site/standard/move-left/ansi
* @see mshop/locale/manager/site/standard/move-right/ansi
* @see mshop/locale/manager/site/standard/update-parentid/ansi
* @see mshop/locale/manager/site/standard/insert-usage/ansi
* @see mshop/locale/manager/site/standard/update-usage/ansi
*/
'search' => str_replace( ':siteid', $siteid, $this->getSqlConfig( 'mshop/locale/manager/site/standard/search' ) ),
/** mshop/locale/manager/site/standard/update/mysql
* Updates an existing catalog node in the database
*
* @see mshop/locale/manager/site/standard/update/ansi
*/
/** mshop/locale/manager/site/standard/update/ansi
* Updates an existing catalog node in the database
*
* Items which already have an ID (i.e. the ID is not NULL) will
* be updated in the database.
*
* The SQL statement must be a string suitable for being used as
* prepared statement. It must include question marks for binding
* the values from the catalog item to the statement before they are
* sent to the database server. The order of the columns must
* correspond to the order in the saveNode() method, so the
* correct values are bound to the columns.
*
* The SQL statement should conform to the ANSI standard to be
* compatible with most relational database systems. This also
* includes using double quotes for table and column names.
*
* @param string SQL statement for updating records
* @since 2014.03
* @category Developer
* @see mshop/locale/manager/site/standard/delete/ansi
* @see mshop/locale/manager/site/standard/get/ansi
* @see mshop/locale/manager/site/standard/insert/ansi
* @see mshop/locale/manager/site/standard/newid/ansi
* @see mshop/locale/manager/site/standard/search/ansi
* @see mshop/locale/manager/site/standard/search-item/ansi
* @see mshop/locale/manager/site/standard/count/ansi
* @see mshop/locale/manager/site/standard/move-left/ansi
* @see mshop/locale/manager/site/standard/move-right/ansi
* @see mshop/locale/manager/site/standard/update-parentid/ansi
* @see mshop/locale/manager/site/standard/insert-usage/ansi
* @see mshop/locale/manager/site/standard/update-usage/ansi
*/
'update' => str_replace( ':siteid', $siteid, $this->getSqlConfig( 'mshop/locale/manager/site/standard/update' ) ),
/** mshop/locale/manager/site/standard/update-parentid/mysql
* Updates the parent ID after moving a node record
*
* @see mshop/locale/manager/site/standard/update-parentid/ansi
*/
/** mshop/locale/manager/site/standard/update-parentid/ansi
* Updates the parent ID after moving a node record
*
* When moving nodes with the catalog tree, the parent ID
* references must be updated to match the new parent.
*
* The SQL statement must be a string suitable for being used as
* prepared statement. It must include question marks for binding
* the values from the catalog item to the statement before they are
* sent to the database server. The order of the columns must
* correspond to the order in the moveNode() method, so the
* correct values are bound to the columns.
*
* The SQL statement should conform to the ANSI standard to be
* compatible with most relational database systems. This also
* includes using double quotes for table and column names.
*
* @param string SQL statement for updating records
* @since 2014.03
* @category Developer
* @see mshop/locale/manager/site/standard/delete/ansi
* @see mshop/locale/manager/site/standard/get/ansi
* @see mshop/locale/manager/site/standard/insert/ansi
* @see mshop/locale/manager/site/standard/update/ansi
* @see mshop/locale/manager/site/standard/newid/ansi
* @see mshop/locale/manager/site/standard/search/ansi
* @see mshop/locale/manager/site/standard/search-item/ansi
* @see mshop/locale/manager/site/standard/count/ansi
* @see mshop/locale/manager/site/standard/move-left/ansi
* @see mshop/locale/manager/site/standard/move-right/ansi
* @see mshop/locale/manager/site/standard/insert-usage/ansi
* @see mshop/locale/manager/site/standard/update-usage/ansi
*/
'update-parentid' => str_replace( ':siteid', $siteid, $this->getSqlConfig( 'mshop/locale/manager/site/standard/update-parentid' ) ),
/** mshop/locale/manager/site/standard/newid/mysql
* Retrieves the ID generated by the database when inserting a new record
*
* @see mshop/locale/manager/site/standard/newid/ansi
*/
/** mshop/locale/manager/site/standard/newid/ansi
* Retrieves the ID generated by the database when inserting a new record
*
* As soon as a new record is inserted into the database table,
* the database server generates a new and unique identifier for
* that record. This ID can be used for retrieving, updating and
* deleting that specific record from the table again.
*
* For MySQL:
* SELECT LAST_INSERT_ID()
* For PostgreSQL:
* SELECT currval('seq_mcat_id')
* For SQL Server:
* SELECT SCOPE_IDENTITY()
* For Oracle:
* SELECT "seq_mcat_id".CURRVAL FROM DUAL
*
* There's no way to retrive the new ID by a SQL statements that
* fits for most database servers as they implement their own
* specific way.
*
* @param string SQL statement for retrieving the last inserted record ID
* @since 2014.03
* @category Developer
* @see mshop/locale/manager/site/standard/delete/ansi
* @see mshop/locale/manager/site/standard/get/ansi
* @see mshop/locale/manager/site/standard/insert/ansi
* @see mshop/locale/manager/site/standard/update/ansi
* @see mshop/locale/manager/site/standard/search/ansi
* @see mshop/locale/manager/site/standard/search-item/ansi
* @see mshop/locale/manager/site/standard/count/ansi
* @see mshop/locale/manager/site/standard/move-left/ansi
* @see mshop/locale/manager/site/standard/move-right/ansi
* @see mshop/locale/manager/site/standard/update-parentid/ansi
* @see mshop/locale/manager/site/standard/insert-usage/ansi
* @see mshop/locale/manager/site/standard/update-usage/ansi
*/
'newid' => $this->getSqlConfig( 'mshop/locale/manager/site/standard/newid' ),
),
);
$this->treeManagers[$siteid] = \Aimeos\MW\Tree\Factory::createManager( 'DBNestedSet', $treeConfig, $dbm );
}
return $this->treeManagers[$siteid];
}
/**
* Creates a flat list node items.
*
* @param \Aimeos\MW\Tree\Node\Iface $node Root node
* @return array Associated list of ID / node object pairs
*/
protected function getNodeMap( \Aimeos\MW\Tree\Node\Iface $node )
{
$map = [];
$map[(string) $node->getId()] = $node;
foreach( $node->getChildren() as $child ) {
$map += $this->getNodeMap( $child );
}
return $map;
}
}
Database Table Setup
Code: Select all
<?php
/**
* @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
* @copyright Aimeos (aimeos.org), 2016-2017
*/
return array(
'table' => array(
'mshop_locale_site' => function ( \Doctrine\DBAL\Schema\Schema $schema ) {
$table = $schema->getTable( 'mshop_locale_site' );
$table->addColumn( 'siteid', 'integer', [] );
$table->addColumn( 'target', 'string', array( 'length' => 255 ) );
return $schema;
},
'mshop_locale_language' => function ( \Doctrine\DBAL\Schema\Schema $schema ) {
$table = $schema->getTable( 'mshop_locale_language' );
return $schema;
},
'mshop_locale_currency' => function ( \Doctrine\DBAL\Schema\Schema $schema ) {
$table = $schema->getTable( 'mshop_locale_currency' );
return $schema;
},
'mshop_locale' => function ( \Doctrine\DBAL\Schema\Schema $schema ) {
$table = $schema->getTable( 'mshop_locale' );
return $schema;
},
),
);
Code: Select all
<?php
return [
'locale' => [
'manager' => [
'name' => 'Sitesubtree',
'site' => [
'name' => 'Nodesites',
'standard' => [
'cleanup' => [
'ansi' => '
DELETE FROM "mshop_locale_site"
WHERE :siteid AND "nleft" >= ? AND "nright" <= ?
'
],
'delete' => [
'ansi' => '
DELETE FROM "mshop_locale_site"
WHERE "siteid" = :siteid AND "nleft" >= ? AND "nright" <= ?
'
],
'get' => [
'ansi' => '
SELECT mlocsi."id", mlocsi."code", mlocsi."label", mlocsi."config",
mlocsi."status", mlocsi."level", mlocsi."parentid", mlocsi."siteid",
mlocsi."nleft" AS "left", mlocsi."nright" AS "right",
mlocsi."mtime", mlocsi."editor", mlocsi."ctime", mlocsi."target"
FROM "mshop_locale_site" AS mlocsi, "mshop_locale_site" AS parent
WHERE mlocsi."siteid" = :siteid AND mlocsi."nleft" >= parent."nleft"
AND mlocsi."nleft" <= parent."nright"
AND parent."siteid" = :siteid AND parent."id" = ?
AND mlocsi."level" <= parent."level" + ? AND :cond
GROUP BY mlocsi."id", mlocsi."code", mlocsi."label", mlocsi."config",
mlocsi."status", mlocsi."level", mlocsi."parentid",
mlocsi."siteid", mlocsi."nleft", mlocsi."nright",
mlocsi."mtime", mlocsi."editor", mlocsi."ctime", mlocsi."target"
ORDER BY mlocsi."nleft"
'
],
'insert' => [
'ansi' => '
INSERT INTO "mshop_locale_site" (
"siteid", "label", "code", "status", "parentid", "level",
"nleft", "nright", "config", "mtime", "ctime", "editor", "target"
) VALUES (
:siteid, ?, ?, ?, ?, ?, ?, ?, \'\', \'1970-01-01 00:00:00\', \'1970-01-01 00:00:00\', \'\', \'\'
)
'
],
'insert-usage' => [
'ansi' => '
UPDATE "mshop_locale_site"
SET "config" = ?, "mtime" = ?, "editor" = ?, "target" = ?, "ctime" = ?
WHERE "siteid" = ? AND "id" = ?
'
],
'update' => [
'ansi' => '
UPDATE "mshop_locale_site"
SET "label" = ?, "code" = ?, "status" = ?
WHERE "siteid" = :siteid AND "id" = ?
'
],
'update-parentid' => [
'ansi' => '
UPDATE "mshop_locale_site"
SET "parentid" = ?
WHERE "siteid" = :siteid AND "id" = ?
'
],
'update-usage' => [
'ansi' => '
UPDATE "mshop_locale_site"
SET "config" = ?, "mtime" = ?, "editor" = ?, "target" = ?
WHERE "siteid" = ? AND "id" = ?
'
],
'move-left' => [
'ansi' => '
UPDATE "mshop_locale_site"
SET "nleft" = "nleft" + ?, "level" = "level" + ?
WHERE "siteid" = :siteid AND "nleft" >= ? AND "nleft" <= ?
'
],
'move-right' => [
'ansi' => '
UPDATE "mshop_locale_site"
SET "nright" = "nright" + ?
WHERE "siteid" = :siteid AND "nright" >= ? AND "nright" <= ?
'
],
'search' => [
'ansi' => '
SELECT mlocsi."id", mlocsi."code", mlocsi."label", mlocsi."config",
mlocsi."status", mlocsi."level", mlocsi."parentid", mlocsi."siteid",
mlocsi."nleft" AS "left", mlocsi."nright" AS "right",
mlocsi."mtime", mlocsi."editor", mlocsi."ctime", mlocsi."target"
FROM "mshop_locale_site" AS mlocsi
WHERE mlocsi."siteid" = :siteid AND mlocsi."nleft" >= ?
AND mlocsi."nright" <= ? AND :cond
GROUP BY mlocsi."id", mlocsi."code", mlocsi."label", mlocsi."config",
mlocsi."status", mlocsi."level", mlocsi."parentid", mlocsi."siteid",
mlocsi."nleft", mlocsi."nright", mlocsi."mtime", mlocsi."editor",
mlocsi."ctime", mlocsi."target"
ORDER BY :order
'
],
'search-item' => [
'ansi' => '
SELECT mlocsi."id", mlocsi."code", mlocsi."label", mlocsi."config",
mlocsi."status", mlocsi."level", mlocsi."parentid", mlocsi."siteid",
mlocsi."nleft" AS "left", mlocsi."nright" AS "right",
mlocsi."mtime", mlocsi."editor", mlocsi."ctime", mlocsi."target"
FROM "mshop_locale_site" AS mlocsi
:joins
WHERE :cond
GROUP BY mlocsi."id", mlocsi."code", mlocsi."label", mlocsi."config",
mlocsi."status", mlocsi."level", mlocsi."parentid", mlocsi."siteid",
mlocsi."nleft", mlocsi."nright", mlocsi."mtime", mlocsi."editor",
mlocsi."ctime", mlocsi."target"
/*-columns*/ , :columns /*columns-*/
/*-orderby*/ ORDER BY :order /*orderby-*/
LIMIT :size OFFSET :start
'
],
'count' => [
'ansi' => '
SELECT COUNT(*) AS "count"
FROM (
SELECT DISTINCT mlocsi."id"
FROM "mshop_locale_site" AS mlocsi
WHERE :cond
LIMIT 10000 OFFSET 0
) AS list
'
],
'count-items' => [
'ansi' => '
SELECT COUNT(*) AS "count"
FROM (
SELECT DISTINCT mlocsi."id"
FROM "mshop_locale_site" AS mlocsi
:joins
WHERE :cond
LIMIT 10000 OFFSET 0
) AS list
'
],
'newid' => [
'db2' => 'SELECT IDENTITY_VAL_LOCAL()',
'mysql' => 'SELECT LAST_INSERT_ID()',
'oracle' => 'SELECT mshop_locale_site_seq.CURRVAL FROM DUAL',
'pgsql' => 'SELECT lastval()',
'sqlite' => 'SELECT last_insert_rowid()',
'sqlsrv' => 'SELECT SCOPE_IDENTITY()',
'sqlanywhere' => 'SELECT @@IDENTITY',
],
'search2' => [
'ansi' => '
SELECT mlocsi."id", mlocsi."code", mlocsi."label", mlocsi."config",
mlocsi."status", mlocsi."level", mlocsi."parentid", mlocsi."siteid",
mlocsi."nleft" AS "left", mlocsi."nright" AS "right",
mlocsi."mtime", mlocsi."editor", mlocsi."ctime", mlocsi."target"
FROM "mshop_locale_site" AS mlocsi
WHERE :cond
GROUP BY mlocsi."id", mlocsi."code", mlocsi."label", mlocsi."config",
mlocsi."status", mlocsi."level", mlocsi."parentid", mlocsi."siteid",
mlocsi."nleft", mlocsi."nright", mlocsi."mtime", mlocsi."editor",
mlocsi."ctime", mlocsi."target"
:columns
ORDER BY :order
LIMIT :size OFFSET :start
'
],
],
],
],
],
];
Last edited by tenkraD on 05 Dec 2018, 13:09, edited 1 time in total.
Re: Multiple Site 1 Basket / Checkout
<Part 3>
Jqadmin Src
Path: /ext/myext/Resources/Private/Extensions/myext/admin/jqadm/src/Admin/JQAdm/Locale/Site/Nodesites.php
Template
Path: /ext/myext/Resources/Private/Extensions/myext/admin/jqadm/templates/locale/site/item-nodesite.php
JS Theme
Path: ext/myext/Resources/Private/Extensions/myext/admin/jqadm/themes/custom.js
Configuration for Admin and Template
Path: ext/myext/Resources/Private/Extensions/myext/config/admin.php
JsonAdmin Src Changes to retrieve Childs of a node and for saving
Path: ext/myext/Resources/Private/Extensions/myext/admin/jsonadm/src/Admin/JsonAdm/Locale/Site/Nodesites.php
Jqadmin Src
Path: /ext/myext/Resources/Private/Extensions/myext/admin/jqadm/src/Admin/JQAdm/Locale/Site/Nodesites.php
Code: Select all
<?php
/**
* @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
* @copyright Aimeos (aimeos.org), 2017
* @package Admin
* @subpackage JQAdm
*/
namespace Aimeos\Admin\JQAdm\Locale\Site;
sprintf( 'locale/site' ); // for translation
/**
* Default implementation of locale site JQAdm client.
*
* @package Admin
* @subpackage JQAdm
*/
class Nodesites
extends Standard
//extends \Aimeos\Admin\JQAdm\Common\Admin\Factory\Base
//implements \Aimeos\Admin\JQAdm\Common\Admin\Factory\Iface
{
/**
* Copies a resource
*
* @return string HTML output
*/
public function copy()
{
$view = $this->getView();
$context = $this->getContext();
try
{
if( ( $id = $view->param( 'id' ) ) === null ) {
throw new \Aimeos\Admin\JQAdm\Exception( sprintf( 'Required parameter "%1$s" is missing', 'id' ) );
}
$this->checkSite( $view->access( 'super' ), $id );
$manager = \Aimeos\MShop\Factory::createManager( $context, 'locale/site' );
$view->item = $manager->getItem( $id );
$view->itemData = $this->toArray( $view->item, true );
$view->itemSubparts = $this->getSubClientNames();
$view->itemRootId = $this->getRootId();
$view->itemBody = '';
foreach( $this->getSubClients() as $idx => $client )
{
$view->tabindex = ++$idx + 1;
$view->itemBody .= $client->copy();
}
}
// catch( \Aimeos\Admin\JQAdm\Exception $e )
// {
// $error = array( 'locale-site-item' => $context->getI18n()->dt( 'admin', $e->getMessage() ) );
// $view->errors = $view->get( 'errors', [] ) + $error;
// $this->logException( $e );
// }
catch( \Aimeos\MShop\Exception $e )
{
$error = array( 'locale-site-item' => $context->getI18n()->dt( 'mshop', $e->getMessage() ) );
$view->errors = $view->get( 'errors', [] ) + $error;
$this->logException( $e );
}
catch( \Exception $e )
{
$error = array( 'locale-site-item' => $e->getMessage() . ', ' . $e->getFile() . ':' . $e->getLine() );
$view->errors = $view->get( 'errors', [] ) + $error;
$this->logException( $e );
}
return $this->render( $view );
}
/**
* Creates a new resource
*
* @return string HTML output
*/
public function create()
{
$view = $this->getView();
$context = $this->getContext();
try
{
$this->checkSite( $view->access( 'super' ) );
$data = $view->param( 'item', [] );
if( !isset( $view->item ) ) {
$view->item = \Aimeos\MShop\Factory::createManager( $context, 'locale/site' )->createItem();
}
// EV ist getSiteId die id dann wäre dies hier richtig - ansonsten unten richtig - $data['locale.site.id'] = $view->item->getSiteId();
$data['locale.site.siteid'] = $view->item->getSiteId();
//$data['locale.site.siteid'] = "1";
$data['locale.site.parentid'] = $view->item->getParentId() ?: $view->param( 'item/locale.site.parentid' );
$view->itemSubparts = $this->getSubClientNames();
$view->itemRootId = $this->getRootId();
$view->itemData = $data;
$view->itemBody = '';
foreach( $this->getSubClients() as $idx => $client )
{
$view->tabindex = ++$idx + 1;
$view->itemBody .= $client->create();
}
}
// catch( \Aimeos\Admin\JQAdm\Exception $e )
// {
// $error = array( 'locale-site-item' => $context->getI18n()->dt( 'admin', $e->getMessage() ) );
// $view->errors = $view->get( 'errors', [] ) + $error;
// $this->logException( $e );
// }
catch( \Aimeos\MShop\Exception $e )
{
$error = array( 'locale-site-item' => $context->getI18n()->dt( 'mshop', $e->getMessage() ) );
$view->errors = $view->get( 'errors', [] ) + $error;
$this->logException( $e );
}
catch( \Exception $e )
{
$error = array( 'locale-site-item' => $e->getMessage() . ', ' . $e->getFile() . ':' . $e->getLine() );
$view->errors = $view->get( 'errors', [] ) + $error;
$this->logException( $e );
}
return $this->render( $view );
}
/**
* Deletes a resource
*
* @return string|null HTML output
*/
public function delete()
{
$view = $this->getView();
$context = $this->getContext();
$manager = \Aimeos\MShop\Factory::createManager( $context, 'locale/site' );
$manager->begin();
try
{
if( ( $id = $view->param( 'id' ) ) === null ) {
throw new \Aimeos\Admin\JQAdm\Exception( sprintf( 'Required parameter "%1$s" is missing', 'id' ) );
}
$this->checkSite( $view->access( 'super' ), $id );
$view->item = $manager->getItem( $id );
foreach( $this->getSubClients() as $client ) {
$client->delete();
}
$manager->saveItem( $view->item );
$manager->deleteItem( $id );
$manager->commit();
$this->nextAction( $view, 'search', 'locale/site', null, 'delete' );
return;
}
// catch( \Aimeos\Admin\JQAdm\Exception $e )
// {
// $error = array( 'locale-site-item' => $context->getI18n()->dt( 'admin', $e->getMessage() ) );
// $view->errors = $view->get( 'errors', [] ) + $error;
// $this->logException( $e );
// }
catch( \Aimeos\MShop\Exception $e )
{
$error = array( 'locale-site-item' => $context->getI18n()->dt( 'mshop', $e->getMessage() ) );
$view->errors = $view->get( 'errors', [] ) + $error;
$this->logException( $e );
}
catch( \Exception $e )
{
$error = array( 'locale-site-item' => $e->getMessage() . ', ' . $e->getFile() . ':' . $e->getLine() );
$view->errors = $view->get( 'errors', [] ) + $error;
$this->logException( $e );
}
$manager->rollback();
return $this->search();
}
/**
* Returns a single resource
*
* @return string HTML output
*/
public function get()
{
$view = $this->getView();
$context = $this->getContext();
try
{
if( ( $id = $view->param( 'id' ) ) === null ) {
throw new \Aimeos\Admin\JQAdm\Exception( sprintf( 'Required parameter "%1$s" is missing', 'id' ) );
}
$this->checkSite( $view->access( 'super' ), $id );
$manager = \Aimeos\MShop\Factory::createManager( $context, 'locale/site' );
$view->item = $manager->getItem( $id );
$view->itemSubparts = $this->getSubClientNames();
$view->itemData = $this->toArray( $view->item );
$view->itemRootId = $this->getRootId();
$view->itemBody = '';
foreach( $this->getSubClients() as $idx => $client )
{
$view->tabindex = ++$idx + 1;
$view->itemBody .= $client->get();
}
}
// catch( \Aimeos\Admin\JQAdm\Exception $e )
// {
// $error = array( 'locale-site-item' => $context->getI18n()->dt( 'admin', $e->getMessage() ) );
// $view->errors = $view->get( 'errors', [] ) + $error;
// $this->logException( $e );
// }
catch( \Aimeos\MShop\Exception $e )
{
$error = array( 'locale-site-item' => $context->getI18n()->dt( 'mshop', $e->getMessage() ) );
$view->errors = $view->get( 'errors', [] ) + $error;
$this->logException( $e );
}
catch( \Exception $e )
{
$error = array( 'locale-site-item' => $e->getMessage() . ', ' . $e->getFile() . ':' . $e->getLine() );
$view->errors = $view->get( 'errors', [] ) + $error;
$this->logException( $e );
}
return $this->render( $view );
}
/**
* Saves the data
*
* @return string HTML output
*/
public function save()
{
$view = $this->getView();
$context = $this->getContext();
$manager = \Aimeos\MShop\Factory::createManager( $context, 'locale/site' );
$manager->begin();
try
{
$view->item = $this->fromArray( $view->param( 'item', [] ), $view->access( 'super' ) );
$view->itemBody = '';
foreach( $this->getSubClients() as $client ) {
$view->itemBody .= $client->save();
}
$manager->saveItem( clone $view->item );
$manager->commit();
$this->nextAction( $view, $view->param( 'next' ), 'locale/site', $view->item->getId(), 'save' );
return;
}
catch( \Aimeos\Admin\JQAdm\Exception $e )
{
// fall through to create
// $error = array( 'locale-site-item' => $context->getI18n()->dt( 'admin', $e->getMessage() ) );
// $view->errors = $view->get( 'errors', [] ) + $error;
// $this->logException( $e );
}
catch( \Aimeos\MShop\Exception $e )
{
$error = array( 'locale-site-item' => $context->getI18n()->dt( 'mshop', $e->getMessage() ) );
$view->errors = $view->get( 'errors', [] ) + $error;
$this->logException( $e );
}
catch( \Exception $e )
{
$error = array( 'locale-site-item' => $e->getMessage() . ', ' . $e->getFile() . ':' . $e->getLine() );
$view->errors = $view->get( 'errors', [] ) + $error;
$this->logException( $e );
}
$manager->rollback();
return $this->create();
}
/**
* Returns a list of resource according to the conditions
*
* @return string HTML output
*/
public function search()
{
$view = $this->getView();
$context = $this->getContext();
try
{
$total = 0;
$params = $this->storeSearchParams( $view->param(), 'locale/site' );
$manager = \Aimeos\MShop\Factory::createManager( $context, 'locale/site' );
$search = $this->initCriteria( $manager->createSearch(), $params );
if( $view->access( 'super' ) === false )
{
$search->setConditions( $search->combine( '&&', [
$search->compare( '==', 'locale.site.id', $this->getUserSiteId() ),
$search->getConditions(),
] ) );
}
$view->items = $manager->searchItems( $search, [], $total );
$view->itemRootId = $this->getRootId();
$view->filterAttributes = $manager->getSearchAttributes( true );
$view->filterOperators = $search->getOperators();
$view->total = $total;
$view->itemBody = '';
foreach( $this->getSubClients() as $client ) {
$view->itemBody .= $client->search();
}
}
catch( \Aimeos\MShop\Exception $e )
{
$error = array( 'locale-item' => $context->getI18n()->dt( 'mshop', $e->getMessage() ) );
$view->errors = $view->get( 'errors', [] ) + $error;
$this->logException( $e );
}
catch( \Exception $e )
{
$error = array( 'locale-item' => $e->getMessage() . ', ' . $e->getFile() . ':' . $e->getLine() );
$view->errors = $view->get( 'errors', [] ) + $error;
$this->logException( $e );
}
/** admin/jqadm/locale/site/template-list
* Relative path to the HTML body template for the locale list.
*
* The template file contains the HTML code and processing instructions
* to generate the result shown in the body of the frontend. The
* configuration string is the path to the template file relative
* to the templates directory (usually in admin/jqadm/templates).
*
* You can overwrite the template file configuration in extensions and
* provide alternative templates. These alternative templates should be
* named like the default one but with the string "default" replaced by
* an unique name. You may use the name of your project for this. If
* you've implemented an alternative client class as well, "default"
* should be replaced by the name of the new class.
*
* @param string Relative path to the template creating the HTML code
* @since 2016.04
* @category Developer
*/
$tplconf = 'admin/jqadm/locale/site/template-list';
$default = 'locale/site/list-standard.php';
return $view->render( $view->config( $tplconf, $default ) );
}
/**
* Returns the sub-client given by its name.
*
* @param string $type Name of the client type
* @param string|null $name Name of the sub-client (Default if null)
* @return \Aimeos\Admin\JQAdm\Iface Sub-client object
*/
public function getSubClient( $type, $name = null )
{
/** admin/jqadm/locale/site/decorators/excludes
* Excludes decorators added by the "common" option from the locale JQAdm client
*
* Decorators extend the functionality of a class by adding new aspects
* (e.g. log what is currently done), executing the methods of the underlying
* class only in certain conditions (e.g. only for logged in users) or
* modify what is returned to the caller.
*
* This option allows you to remove a decorator added via
* "client/jqadm/common/decorators/default" before they are wrapped
* around the JQAdm client.
*
* admin/jqadm/locale/site/decorators/excludes = array( 'decorator1' )
*
* This would remove the decorator named "decorator1" from the list of
* common decorators ("\Aimeos\Admin\JQAdm\Common\Decorator\*") added via
* "client/jqadm/common/decorators/default" to the JQAdm client.
*
* @param array List of decorator names
* @since 2017.10
* @category Developer
* @see admin/jqadm/common/decorators/default
* @see admin/jqadm/locale/site/decorators/global
* @see admin/jqadm/locale/site/decorators/local
*/
/** admin/jqadm/locale/site/decorators/global
* Adds a list of globally available decorators only to the locale JQAdm client
*
* Decorators extend the functionality of a class by adding new aspects
* (e.g. log what is currently done), executing the methods of the underlying
* class only in certain conditions (e.g. only for logged in users) or
* modify what is returned to the caller.
*
* This option allows you to wrap global decorators
* ("\Aimeos\Admin\JQAdm\Common\Decorator\*") around the JQAdm client.
*
* admin/jqadm/locale/site/decorators/global = array( 'decorator1' )
*
* This would add the decorator named "decorator1" defined by
* "\Aimeos\Admin\JQAdm\Common\Decorator\Decorator1" only to the JQAdm client.
*
* @param array List of decorator names
* @since 2017.10
* @category Developer
* @see admin/jqadm/common/decorators/default
* @see admin/jqadm/locale/site/decorators/excludes
* @see admin/jqadm/locale/site/decorators/local
*/
/** admin/jqadm/locale/site/decorators/local
* Adds a list of local decorators only to the locale JQAdm client
*
* Decorators extend the functionality of a class by adding new aspects
* (e.g. log what is currently done), executing the methods of the underlying
* class only in certain conditions (e.g. only for logged in users) or
* modify what is returned to the caller.
*
* This option allows you to wrap local decorators
* ("\Aimeos\Admin\JQAdm\Locale\Site\Decorator\*") around the JQAdm client.
*
* admin/jqadm/locale/site/decorators/local = array( 'decorator2' )
*
* This would add the decorator named "decorator2" defined by
* "\Aimeos\Admin\JQAdm\Locale\Site\Decorator\Decorator2" only to the JQAdm client.
*
* @param array List of decorator names
* @since 2017.10
* @category Developer
* @see admin/jqadm/common/decorators/default
* @see admin/jqadm/locale/site/decorators/excludes
* @see admin/jqadm/locale/site/decorators/global
*/
return $this->createSubClient( 'locale/site' . $type, $name );
}
/**
* Returns the IDs of the root locale site
*
* @return string|null ID of the root locale site
*/
protected function getRootId()
{
$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'locale/site' );
try {
return $manager->getTree( null, [], \Aimeos\MW\Tree\Manager\Base::LEVEL_ONE )->getId();
} catch( \Exception $e ) {
return null;
}
}
/**
* Checks if the user is allowed to access the site item
*
* @param boolean $super True if user is a super user
* @param string $id ID of the site to access
* @throws \Aimeos\Admin\JQAdm\Exception If user isn't allowed to access the site
*/
protected function checkSite( $super, $id = null )
{
if( $super === true || (string) $this->getUserSiteId() === (string) $id ) {
return;
}
throw new \Aimeos\Admin\JQAdm\Exception( sprintf( 'Permission denied' ) );
}
/**
* Returns the site ID of the current user
*
* @return string|null Site ID of the current user
*/
protected function getUserSiteId()
{
$context = $this->getContext();
$manager = \Aimeos\MShop\Factory::createManager( $context, 'customer' );
return $manager->getItem( $context->getUserId() )->getSiteId();
}
/**
* Returns the list of sub-client names configured for the client.
*
* @return array List of JQAdm client names
*/
protected function getSubClientNames()
{
/** admin/jqadm/locale/site/standard/subparts
* List of JQAdm sub-clients rendered within the locale section
*
* The output of the frontend is composed of the code generated by the JQAdm
* clients. Each JQAdm client can consist of serveral (or none) sub-clients
* that are responsible for rendering certain sub-parts of the output. The
* sub-clients can contain JQAdm clients themselves and therefore a
* hierarchical tree of JQAdm clients is composed. Each JQAdm client creates
* the output that is placed inside the container of its parent.
*
* At first, always the JQAdm code generated by the parent is printed, then
* the JQAdm code of its sub-clients. The order of the JQAdm sub-clients
* determines the order of the output of these sub-clients inside the parent
* container. If the configured list of clients is
*
* array( "subclient1", "subclient2" )
*
* you can easily change the order of the output by reordering the subparts:
*
* admin/jqadm/<clients>/subparts = array( "subclient1", "subclient2" )
*
* You can also remove one or more parts if they shouldn't be rendered:
*
* admin/jqadm/<clients>/subparts = array( "subclient1" )
*
* As the clients only generates structural JQAdm, the layout defined via CSS
* should support adding, removing or reordering content by a fluid like
* design.
*
* @param array List of sub-client names
* @since 2017.10
* @category Developer
*/
return $this->getContext()->getConfig()->get( 'admin/jqadm/locale/site/standard/subparts', [] );
}
/**
* Creates new and updates existing items using the data array
*
* @param string[] $data Data array
* @param boolean $super If current user is a super user
* @return \Aimeos\MShop\Locale\Item\Iface New locale item object
*/
protected function fromArray( array $data, $super )
{
$conf = [];
if( isset( $data['config']['key'] ) )
{
foreach( (array) $data['config']['key'] as $idx => $key )
{
if( trim( $key ) !== '' && isset( $data['config']['val'][$idx] ) ) {
$conf[$key] = $data['config']['val'][$idx];
}
}
}
$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'locale/site' );
if( isset( $data['locale.site.id'] ) && $data['locale.site.id'] != '' )
{
$this->checkSite( $super, $data['locale.site.id'] );
$item = $manager->getItem( $data['locale.site.id'] );
}
else
{
$this->checkSite( $super );
$item = $manager->createItem();
}
$item->fromArray( $data );
$item->setConfig( $conf );
if( $item->getId() == null ) {
return $manager->insertItem( $item, $data['locale.site.parentid'] ?: null );
}
return $manager->saveItem( $item );
}
/**
* Constructs the data array for the view from the given item
*
* @param \Aimeos\MShop\Locale\Item\Iface $item Locale item object
* @return string[] Multi-dimensional associative list of item data
*/
protected function toArray( \Aimeos\MShop\Locale\Item\Site\Iface $item, $copy = false )
{
$data = $item->toArray( true );
$data['config'] = [];
if( $copy === true )
{
$data['locale.site.id'] = '';
$data['locale.site.siteid'] = $item->getSiteId();
$data['locale.site.code'] = $data['locale.site.code'] . '_copy';
}
foreach( $item->getConfig() as $key => $value )
{
$data['config']['key'][] = $key;
$data['config']['val'][] = $value;
}
return $data;
}
/**
* Returns the rendered template including the view data
*
* @return string HTML output
*/
protected function render( \Aimeos\MW\View\Iface $view )
{
/** admin/jqadm/locale/site/template-item
* Relative path to the HTML body template for the locale item.
*
* The template file contains the HTML code and processing instructions
* to generate the result shown in the body of the frontend. The
* configuration string is the path to the template file relative
* to the templates directory (usually in admin/jqadm/templates).
*
* You can overwrite the template file configuration in extensions and
* provide alternative templates. These alternative templates should be
* named like the default one but with the string "default" replaced by
* an unique name. You may use the name of your project for this. If
* you've implemented an alternative client class as well, "default"
* should be replaced by the name of the new class.
*
* @param string Relative path to the template creating the HTML code
* @since 2017.10
* @category Developer
*/
$tplconf = 'admin/jqadm/locale/site/template-item';
$default = 'locale/site/item-nodesite.php';
//$default = 'locale/site/item-standard.php';
return $view->render( $view->config( $tplconf, $default ) );
}
}
Path: /ext/myext/Resources/Private/Extensions/myext/admin/jqadm/templates/locale/site/item-nodesite.php
Code: Select all
<?php
/**
* @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
* @copyright Aimeos (aimeos.org), 2017
*/
$selected = function( $key, $code ) {
return ( $key == $code ? 'selected="selected"' : '' );
};
$enc = $this->encoder();
$target = $this->config( 'admin/jqadm/url/save/target' );
$cntl = $this->config( 'admin/jqadm/url/save/controller', 'Jqadm' );
$action = $this->config( 'admin/jqadm/url/save/action', 'save' );
$config = $this->config( 'admin/jqadm/url/save/config', [] );
$listTarget = $this->config( 'admin/jqadm/url/search/target' );
$listCntl = $this->config( 'admin/jqadm/url/search/controller', 'Jqadm' );
$listAction = $this->config( 'admin/jqadm/url/search/action', 'search' );
$listConfig = $this->config( 'admin/jqadm/url/search/config', [] );
$getTarget = $this->config( 'admin/jqadm/url/get/target' );
$getCntl = $this->config( 'admin/jqadm/url/get/controller', 'Jqadm' );
$getAction = $this->config( 'admin/jqadm/url/get/action', 'get' );
$getConfig = $this->config( 'admin/jqadm/url/get/config', [] );
$newTarget = $this->config( 'admin/jqadm/url/create/target' );
$newCntl = $this->config( 'admin/jqadm/url/create/controller', 'Jqadm' );
$newAction = $this->config( 'admin/jqadm/url/create/action', 'create' );
$newConfig = $this->config( 'admin/jqadm/url/create/config', [] );
$jsonTarget = $this->config( 'admin/jsonadm/url/target' );
$jsonCntl = $this->config( 'admin/jsonadm/url/controller', 'Jsonadm' );
$jsonAction = $this->config( 'admin/jsonadm/url/action', 'get' );
$jsonConfig = $this->config( 'admin/jsonadm/url/config', [] );
$params = $this->get( 'pageParams', [] );
?>
<?php $this->block()->start( 'jqadm_content' ); ?>
<form class="item item-locale-site item-tree form-horizontal" method="POST" enctype="multipart/form-data"
action="<?= $enc->attr( $this->url( $target, $cntl, $action, $params, [], $config ) ); ?>"
data-rootid="<?= $enc->attr( $this->get( 'itemRootId' ) ); ?>"
data-geturl="<?= $enc->attr( $this->url( $getTarget, $getCntl, $getAction, ['resource' => 'locale/site', 'id' => '_ID_'] + $params, [], $getConfig ) ); ?>"
data-createurl="<?= $enc->attr( $this->url( $newTarget, $newCntl, $newAction, ['resource' => 'locale/site', 'id' => '_ID_'] + $params, [], $newConfig ) ); ?>"
data-jsonurl="<?= $enc->attr( $this->url( $jsonTarget, $jsonCntl, $jsonAction, ['resource' => 'locale/site'], [], $jsonConfig ) ); ?>"
data-idname="<?= $this->formparam( 'id' ); ?>" >
<input id="item-id" type="hidden" name="<?= $enc->attr( $this->formparam( array( 'item', 'locale.site.id' ) ) ); ?>"
value="<?= $enc->attr( $this->get( 'itemData/locale.site.id' ) ); ?>" />
<input id="item-parentid" type="hidden" name="<?= $enc->attr( $this->formparam( array( 'item', 'locale.site.parentid' ) ) ); ?>"
value="<?= $enc->attr( $this->get( 'itemData/locale.site.parentid', $this->param( 'id', $this->get( 'itemRootId' ) ) ) ); ?>" />
<input id="item-next" type="hidden" name="<?= $enc->attr( $this->formparam( array( 'next' ) ) ); ?>" value="get" />
<?= $this->csrf()->formfield(); ?>
<nav class="main-navbar">
<span class="navbar-brand">
<?= $enc->html( $this->translate( 'admin', 'Site' ) ); ?>:
<?php if( $this->get( 'itemData/locale.site.id' ) ) : ?>
<?= $enc->html( $this->get( 'itemData/locale.site.id' ) ); ?> -
<?php endif; ?>
<?= $enc->html( $this->get( 'itemData/locale.site.label', $this->translate( 'admin', 'New' ) ) ); ?>
<?php if( $this->get( 'itemData/locale.site.siteid' ) ) : ?>
<span class="navbar-secondary">(<?= $enc->html( $this->site()->match( $this->get( 'itemData/locale.site.siteid' ) ) ); ?>)</span>
<?php endif; ?>
</span>
<div class="item-actions">
<?php if( isset( $this->itemData ) ) : ?>
<?= $this->partial( $this->config( 'admin/jqadm/partial/itemactions', 'common/partials/itemactions-standard.php' ), ['params' => $params] ); ?>
<?php else : ?>
<span class="placeholder"> </span>
<?php endif; ?>
</div>
</nav>
<div class="row item-container">
<div class="col-lg-3 locale-site-tree">
<div class="tree-toolbar input-group">
<div class="input-group-prepend">
<span class="btn btn-secondary fa expand-all" tabindex="1"></span>
<span class="btn btn-secondary fa collapse-all" tabindex="1"></span>
</div>
<input type="text" class="form-control search-input" tabindex="1" placeholder="<?= $enc->attr( $this->translate( 'admin', 'Find Site' ) ); ?>">
<div class="input-group-append">
<span class="btn btn-secondary fa act-delete " tabindex="1"></span>
<span class="btn btn-primary fa act-add" tabindex="1"></span>
</div>
</div>
<div class="tree-content">
</div>
</div>
<?php if( isset( $this->itemData ) ) : ?>
<div class="col-lg-9 locale-site-content">
<div class="row">
<div class="col-xl-12 item-navbar">
<ul class="nav nav-tabs flex-row flex-wrap d-flex justify-content-between" role="tablist">
<li class="nav-item basic">
<a class="nav-link active" href="#basic" data-toggle="tab" role="tab" aria-expanded="true" aria-controls="basic" tabindex="1">
<?= $enc->html( $this->translate( 'admin', 'Basic' ) ); ?>
</a>
</li>
<?php foreach( array_values( $this->get( 'itemSubparts', [] ) ) as $idx => $subpart ) : ?>
<li class="nav-item <?= $enc->attr( $subpart ); ?>">
<a class="nav-link" href="#<?= $enc->attr( $subpart ); ?>" data-toggle="tab" role="tab" tabindex="<?= ++$idx+1; ?>">
<?= $enc->html( $this->translate( 'admin', $subpart ) ); ?>
</a>
</li>
<?php endforeach; ?>
</ul>
<div class="item-meta text-muted">
<small>
<?= $enc->html( $this->translate( 'admin', 'Modified' ) ); ?>:
<span class="meta-value"><?= $enc->html( $this->get( 'itemData/locale.site.mtime' ) ); ?></span>
</small>
<small>
<?= $enc->html( $this->translate( 'admin', 'Created' ) ); ?>:
<span class="meta-value"><?= $enc->html( $this->get( 'itemData/locale.site.ctime' ) ); ?></span>
</small>
<small>
<?= $enc->html( $this->translate( 'admin', 'Editor' ) ); ?>:
<span class="meta-value"><?= $enc->html( $this->get( 'itemData/locale.site.editor' ) ); ?></span>
</small>
</div>
</div>
<div class="col-xl-12 item-content tab-content">
<div id="basic" class="row item-basic tab-pane fade show active" role="tabpanel" aria-labelledby="basic">
<div class="col-xl-6 content-block">
<div class="form-group row mandatory">
<label class="col-sm-4 form-control-label"><?= $enc->html( $this->translate( 'admin', 'Status' ) ); ?></label>
<div class="col-sm-8">
<select class="form-control custom-select item-status" required="required" tabindex="1"
name="<?= $enc->attr( $this->formparam( array( 'item', 'locale.site.status' ) ) ); ?>" >
<option value="">
<?= $enc->attr( $this->translate( 'admin', 'Please select' ) ); ?>
</option>
<option value="1" <?= $selected( $this->get( 'itemData/locale.site.status', 1 ), 1 ); ?> >
<?= $enc->html( $this->translate( 'mshop/code', 'status:1' ) ); ?>
</option>
<option value="0" <?= $selected( $this->get( 'itemData/locale.site.status', 1 ), 0 ); ?> >
<?= $enc->html( $this->translate( 'mshop/code', 'status:0' ) ); ?>
</option>
<option value="-1" <?= $selected( $this->get( 'itemData/locale.site.status', 1 ), -1 ); ?> >
<?= $enc->html( $this->translate( 'mshop/code', 'status:-1' ) ); ?>
</option>
<option value="-2" <?= $selected( $this->get( 'itemData/locale.site.status', 1 ), -2 ); ?> >
<?= $enc->html( $this->translate( 'mshop/code', 'status:-2' ) ); ?>
</option>
</select>
</div>
</div>
<div class="form-group row mandatory warning">
<label class="col-sm-4 form-control-label help"><?= $enc->html( $this->translate( 'admin', 'Code' ) ); ?></label>
<div class="col-sm-8">
<input class="form-control item-code" required="required" tabindex="1" autocomplete="off"
name="<?= $enc->attr( $this->formparam( array( 'item', 'locale.site.code' ) ) ); ?>"
placeholder="<?= $enc->attr( $this->translate( 'admin', 'Unique site code (required)' ) ); ?>"
value="<?= $enc->attr( $this->get( 'itemData/locale.site.code' ) ); ?>" />
</div>
<div class="col-sm-12 form-text text-muted help-text">
<?= $enc->html( $this->translate( 'admin', 'Code to uniquely identify the site, renaming is dangerous!' ) ); ?>
</div>
</div>
<div class="form-group row mandatory">
<label class="col-sm-4 form-control-label help"><?= $enc->html( $this->translate( 'admin', 'Label' ) ); ?></label>
<div class="col-sm-8">
<input class="form-control item-label" required="required" tabindex="1" autocomplete="off"
name="<?= $enc->attr( $this->formparam( array( 'item', 'locale.site.label' ) ) ); ?>"
placeholder="<?= $enc->attr( $this->translate( 'admin', 'Label (required)' ) ); ?>"
value="<?= $enc->attr( $this->get( 'itemData/locale.site.label' ) ); ?>" />
</div>
<div class="col-sm-12 form-text text-muted help-text">
<?= $enc->html( $this->translate( 'admin', 'Descritive name of the site' ) ); ?>
</div>
</div>
<div class="form-group row optional warning">
<label class="col-sm-4 form-control-label help"><?= $enc->html( $this->translate( 'admin', 'URL target' ) ); ?></label>
<div class="col-sm-8">
<input class="form-control item-target" type="text" tabindex="1"
name="<?= $enc->attr( $this->formparam( array( 'item', 'locale.site.target' ) ) ); ?>"
placeholder="<?= $enc->attr( $this->translate( 'admin', 'Route or page ID (optional)' ) ); ?>"
value="<?= $enc->attr( $this->get( 'itemData/locale.site.target' ) ); ?>"
<?= $this->site()->readonly( $this->get( 'itemData/locale.site.siteid' ) ); ?> />
</div>
<div class="col-sm-12 form-text text-muted help-text">
<?= $enc->html( $this->translate( 'admin', 'Route name or page ID of the category page if this category should shown on a different page' ) ); ?>
</div>
</div>
</div><!--
--><div class="col-xl-6 content-block">
<table class="item-config table table-striped">
<thead>
<tr>
<th>
<span class="help"><?= $enc->html( $this->translate( 'admin', 'Option' ) ); ?></span>
<div class="form-text text-muted help-text">
<?= $enc->html( $this->translate( 'admin', 'Site specific configuration options, will be available as key/value pairs' ) ); ?>
</div>
</th>
<th>
<?= $enc->html( $this->translate( 'admin', 'Value' ) ); ?>
</th>
<th class="actions">
<div class="btn act-add fa" tabindex="1"
title="<?= $enc->attr( $this->translate( 'admin', 'Insert new entry (Ctrl+I)') ); ?>">
</div>
</th>
</tr>
</thead>
<tbody>
<?php foreach( (array) $this->get( 'itemData/config/key', [] ) as $idx => $key ) : ?>
<tr class="config-item">
<td>
<input type="text" class="config-key form-control" tabindex="1"
name="<?= $enc->attr( $this->formparam( array( 'item', 'config', 'key', '' ) ) ); ?>"
value="<?= $enc->attr( $this->get( 'itemData/config/key/' . $idx, $key ) ); ?>" />
</td>
<td>
<input type="text" class="config-value form-control" tabindex="1"
name="<?= $enc->attr( $this->formparam( array( 'item', 'config', 'val', '' ) ) ); ?>"
value="<?= $enc->attr( $this->get( 'itemData/config/val/' . $idx ) ); ?>" />
</td>
<td class="actions">
<div class="btn act-delete fa" tabindex="1"
title="<?= $enc->attr( $this->translate( 'admin', 'Delete this entry') ); ?>">
</div>
</td>
</tr>
<?php endforeach; ?>
<tr class="prototype">
<td>
<input type="text" class="config-key form-control" tabindex="1" disabled="disabled"
name="<?= $enc->attr( $this->formparam( array( 'item', 'config', 'key', '' ) ) ); ?>" />
</td>
<td>
<input type="text" class="config-value form-control" tabindex="1" disabled="disabled"
name="<?= $enc->attr( $this->formparam( array( 'item', 'config', 'val', '' ) ) ); ?>" />
</td>
<td class="actions">
<div class="btn act-delete fa" tabindex="1"
title="<?= $enc->attr( $this->translate( 'admin', 'Delete this entry') ); ?>">
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<?= $this->get( 'itemBody' ); ?>
</div>
<div class="item-actions">
<?= $this->partial( $this->config( 'admin/jqadm/partial/itemactions', 'common/partials/itemactions-standard.php' ), ['params' => $params] ); ?>
</div>
</div>
</div>
<?php endif; ?>
</div>
</form>
<?php $this->block()->stop(); ?>
<?= $this->render( $this->config( 'admin/jqadm/template/page', 'common/page-standard.php' ) ); ?>
Path: ext/myext/Resources/Private/Extensions/myext/admin/jqadm/themes/custom.js
Code: Select all
/*
* Custom mhaimeos2018 JS
*/
/**
* @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
* @copyright Aimeos (aimeos.org), 2017
*/
/**
* Attention:
*
* Updating tree.jquery.js requires removing or overwriting these lines from
* NodeElement.prototype.select() and NodeElement.prototype.deselect():
*
* var $span = this.getSpan();
* $span.attr("tabindex", 0);
* $span.focus();
*/
/**
* Load Locale Sites and create catalog tree
*/
Aimeos.options.done(function(result) {
var rootId = $(".aimeos .item-locale-site").data("rootid");
if(!rootId || !result || !result.meta || !result.meta.resources || !result.meta.resources["locale\/site"]) {
return;
}
var params = {};
if(result.meta.prefix) {
Aimeos.Localesite.prefix = result.meta.prefix;
params[result.meta.prefix] = {id: rootId, include: "locale.site"};
} else {
params = {id: rootId, include: "locale.site"};
}
$.ajax(result.meta.resources["locale\/site"], {
"data": params,
"dataType": "json"
}).done(function(result) {
if(!result || !result.data || !result.meta) {
throw {"msg": "No valid data in response", "result": result};
}
if(result.meta.csrf) {
Aimeos.Localesite.csrf = result.meta.csrf;
}
var root = Aimeos.Localesite.createTree(Aimeos.Localesite.transformNodes(result));
root.bind("tree.click", Aimeos.Localesite.onClick);
root.bind("tree.move", Aimeos.Localesite.onMove);
var id = $(".aimeos .item-locale-site #item-id").val() || $(".aimeos .item-locale-site #item-parentid").val();
var node = root.tree("getNodeById", id);
root.tree("selectNode", node);
root.tree("openNode", node);
});
});
Aimeos.Localesite = {
csrf : null,
element : null,
prefix: null,
init : function() {
this.askDelete();
this.confirmDelete();
this.setupAdd();
this.setupSearch();
this.setupExpandAll();
this.setupCollapseAll();
},
createTree : function(root) {
var tree = $(".aimeos .item-locale-site .tree-content").tree({
"data": [root],
"dragAndDrop": true,
"closedIcon": " ",
"openedIcon": " ",
"saveState": true,
"slide": false,
"dataFilter": function(result) {
var list = [];
for(var i in result.included) {
if(result.included[i].type !== 'locale\/site') {
continue;
}
list.push({
id: result.included[i].id,
name: result.included[i].attributes['locale.site.label'],
load_on_demand: result.included[i].attributes['locale.site.hasChildren'],
children: []
});
}
return list;
},
dataUrl: function(node) {
var params = {};
if(Aimeos.Localesite.prefix) {
params[Aimeos.Localesite.prefix] = {'include': 'locale.site'};
} else {
params = {'include': 'locale.site'};
}
var result = {
'url': $(".aimeos .item-tree").data("jsonurl"),
'data': params,
'method': 'GET'
}
if(node) {
var name = $(".aimeos .item-tree").data("idname");
result['data'][name] = node.id;
}
return result;
},
"onCanMoveTo": function(node, target, position) {
if(target === tree.tree('getTree').children[0] && position !== 'inside') {
return false;
}
return true;
},
"onCreateLi": function(node, li, isselected) {
$(".jqtree-toggler", li).attr("tabindex", 1);
$(".jqtree-title", li).attr("tabindex", 1);
}
});
return tree;
},
onClick : function(event) {
window.location = $(".aimeos .item-locale-site").data("geturl").replace("_ID_", event.node.id);
},
onMove : function(event) {
event.preventDefault();
Aimeos.options.done(function(result) {
if(!result || !result.meta || !result.meta.resources || !result.meta.resources["locale\/site"]) {
throw {"msg": "No valid data in response", "result": result};
}
var params = {};
var url = result.meta.resources["locale\/site"];
var targetid = event.move_info.target_node.id;
if(result.meta.prefix) {
params[result.meta.prefix] = {id: event.move_info.moved_node.id};
} else {
params = {id: event.move_info.moved_node.id};
}
if(Aimeos.Localesite.csrf) {
params[Aimeos.Localesite.csrf.name] = Aimeos.Localesite.csrf.value;
}
var entry = {
attributes: {},
id: event.move_info.moved_node.id,
parentid: event.move_info.previous_parent.id
};
if(event.move_info.position === 'inside') {
entry.targetid = targetid;
} else {
entry.targetid = event.move_info.target_node.parent.id;
}
if(event.move_info.position === 'after') {
var children = event.move_info.target_node.parent.children;
for(var i = 0; i < children.length; i++) {
if(children[i].id === targetid && i+1 < children.length) {
entry.refid = children[i+1].id;
break;
}
}
} else if(event.move_info.position === 'before') {
entry.refid = targetid;
}
$.ajax(url + (url.indexOf('?') !== -1 ? '&' : '?') + jQuery.param(params), {
"dataType": "json",
"method": "PATCH",
"data": JSON.stringify({"data": entry})
}).done(function(result) {
event.move_info.do_move();
if(result.meta.csrf) {
Aimeos.Localesite.csrf = result.meta.csrf;
}
});
});
},
transformNodes : function(result) {
root = {
id: result.data.id,
name: result.data.attributes['locale.site.label'] || '-none-',
children: []
};
if(result.included && result.included.length > 0) {
var getChildren = function(list, parentId) {
var result = [];
for(var i in list) {
if(list[i].attributes['locale.site.parentid'] == parentId) {
result.push({
id: list[i].id,
name: list[i].attributes['locale.site.label'],
load_on_demand: list[i].attributes['locale.site.hasChildren'],
children: getChildren(list, list[i].id)
});
}
}
return result;
};
root.children = getChildren(result.included, result.data.id);
}
return root;
},
askDelete : function() {
var self = this;
$(".aimeos .item-locale-site").on("click", ".tree-toolbar .act-delete", function(ev) {
$("#confirm-delete").modal("show", $(this));
self.element = $(".tree-content", ev.delegateTarget).tree("getSelectedNode");
return false;
});
},
confirmDelete : function() {
var self = this;
$("#confirm-delete").on("click", ".btn-danger", function(e) {
if(self.element) {
self.deleteNode(self.element, self.element.parent || null);
}
});
},
deleteNode : function(node, parent) {
Aimeos.options.done(function(result) {
if(!result || !result.meta || !result.meta.resources || !result.meta.resources["locale\/site"]) {
throw {"msg": "No valid data in response", "result": result};
}
var params = {};
var url = result.meta.resources["locale\/site"];
if(result.meta.prefix) {
params[result.meta.prefix] = {id: node.id};
} else {
params = {id: node.id};
}
if(Aimeos.Localesite.csrf) {
params[Aimeos.Localesite.csrf.name] = Aimeos.Localesite.csrf.value;
}
$.ajax(url + (url.indexOf('?') !== -1 ? '&' : '?') + jQuery.param(params), {
"dataType": "json",
"method": "DELETE"
}).done(function(result) {
if(result.meta.csrf) {
Aimeos.Localesite.csrf = result.meta.csrf;
}
if(!result.errors) {
window.location = $(".aimeos .item-locale-site").data("createurl").replace("_ID_", (parent && parent.id ? parent.id : ''));
}
});
});
},
setupAdd : function() {
$(".aimeos .item-locale-site").on("click", ".tree-toolbar .act-add", function(ev) {
var root = $(".tree-content", ev.delegateTarget);
var node = root.tree("getSelectedNode");
if(!node) {
node = root.tree("getNodeByHtmlElement", $(".jqtree-tree > .jqtree-folder", root));
}
window.location = $(ev.delegateTarget).data("createurl").replace("_ID_", (node ? node.id : ''));
});
},
setupCollapseAll : function() {
$(".aimeos .item-locale-site .locale-site-tree").on("click", ".tree-toolbar .collapse-all", function(ev) {
$(".tree-content .jqtree-folder .jqtree-toggler", ev.delegateTarget).addClass("jqtree-closed");
$(".tree-content .jqtree-folder", ev.delegateTarget).addClass("jqtree-closed");
$('.tree-content ul.jqtree_common[role="group"]', ev.delegateTarget).css("display", "none");
});
},
setupExpandAll : function() {
$(".aimeos .item-locale-site .locale-site-tree").on("click", ".tree-toolbar .expand-all", function(ev) {
$(".tree-content .jqtree-folder .jqtree-toggler.jqtree-closed", ev.delegateTarget).removeClass("jqtree-closed");
$(".tree-content .jqtree-folder.jqtree-closed", ev.delegateTarget).removeClass("jqtree-closed");
$('.tree-content ul.jqtree_common[role="group"]', ev.delegateTarget).css("display", "block");
});
},
setupSearch : function() {
$(".aimeos .locale-site-tree .tree-toolbar").on("input", ".search-input", function() {
var name = $(this).val();
$('.aimeos .locale-site-tree .tree-content .jqtree_common[role="treeitem"]').each(function(idx, node) {
var regex = new RegExp(name, 'i');
var node = $(node);
if(regex.test(node.html())) {
node.parents("li.jqtree_common").show();
node.show();
} else {
node.hide();
}
});
});
}
};
$(function() {
Aimeos.Localesite.init();
});
Path: ext/myext/Resources/Private/Extensions/myext/config/admin.php
Code: Select all
<?php
return [
'jqadm' => [
'locale' => [
'site' => [
'name' => 'Nodesites',
],
],
],
'jsonadm' => [
],
];
Path: ext/myext/Resources/Private/Extensions/myext/admin/jsonadm/src/Admin/JsonAdm/Locale/Site/Nodesites.php
Code: Select all
<?php
/**
* @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
* @copyright Aimeos (aimeos.org), 2016-2017
* @package Admin
* @subpackage JsonAdm
*/
namespace Aimeos\Admin\JsonAdm\Locale\Site;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
* JSON API locale site client
*
* @package Admin
* @subpackage JsonAdm
*/
class Mystandard
extends \Aimeos\Admin\JsonAdm\Standard
implements \Aimeos\Admin\JsonAdm\Common\Iface
{
/** admin/jsonadm/locale/site/decorators/excludes
* Excludes decorators added by the "common" option from the JSON API clients
*
* Decorators extend the functionality of a class by adding new aspects
* (e.g. log what is currently done), executing the methods of the underlying
* class only in certain conditions (e.g. only for logged in users) or
* modify what is returned to the caller.
*
* This option allows you to remove a decorator added via
* "admin/jsonadm/common/decorators/default" before they are wrapped
* around the Jsonadm client.
*
* admin/jsonadm/decorators/excludes = array( 'decorator1' )
*
* This would remove the decorator named "decorator1" from the list of
* common decorators ("\Aimeos\Admin\JsonAdm\Common\Decorator\*") added via
* "admin/jsonadm/common/decorators/default" for the JSON API client.
*
* @param array List of decorator names
* @since 2016.01
* @category Developer
* @see admin/jsonadm/common/decorators/default
* @see admin/jsonadm/locale/site/decorators/global
* @see admin/jsonadm/locale/site/decorators/local
*/
/** admin/jsonadm/locale/site/decorators/global
* Adds a list of globally available decorators only to the Jsonadm client
*
* Decorators extend the functionality of a class by adding new aspects
* (e.g. log what is currently done), executing the methods of the underlying
* class only in certain conditions (e.g. only for logged in users) or
* modify what is returned to the caller.
*
* This option allows you to wrap global decorators
* ("\Aimeos\Admin\Jsonadm\Common\Decorator\*") around the Jsonadm
* client.
*
* admin/jsonadm/locale/site/decorators/global = array( 'decorator1' )
*
* This would add the decorator named "decorator1" defined by
* "\Aimeos\Admin\Jsonadm\Common\Decorator\Decorator1" only to the
* "locale/site " Jsonadm client.
*
* @param array List of decorator names
* @since 2016.01
* @category Developer
* @see admin/jsonadm/common/decorators/default
* @see admin/jsonadm/locale/site/decorators/excludes
* @see admin/jsonadm/locale/site/decorators/local
*/
/** admin/jsonadm/locale/site/decorators/local
* Adds a list of local decorators only to the Jsonadm client
*
* Decorators extend the functionality of a class by adding new aspects
* (e.g. log what is currently done), executing the methods of the underlying
* class only in certain conditions (e.g. only for logged in users) or
* modify what is returned to the caller.
*
* This option allows you to wrap local decorators
* ("\Aimeos\Admin\Jsonadm\Catalog\Decorator\*") around the Jsonadm
* client.
*
* admin/jsonadm/locale/site/decorators/local = array( 'decorator2' )
*
* This would add the decorator named "decorator2" defined by
* "\Aimeos\Admin\Jsonadm\Catalog\Decorator\Decorator2" only to the
* "locale/site " Jsonadm client.
*
* @param array List of decorator names
* @since 2016.01
* @category Developer
* @see admin/jsonadm/common/decorators/default
* @see admin/jsonadm/locale/site/decorators/excludes
* @see admin/jsonadm/locale/site/decorators/global
*/
/**
* Returns the requested resource or the resource list
*
* @param \Psr\Http\Message\ServerRequestInterface $request Request object
* @param \Psr\Http\Message\ResponseInterface $response Response object
* @return \Psr\Http\Message\ResponseInterface Modified response object
*/
public function get( ServerRequestInterface $request, ResponseInterface $response )
{
/** admin/jsonadm/partials/locale/site/template-data
* Relative path to the data partial template file for the locale site client
*
* Partials are templates which are reused in other templates and generate
* reoccuring blocks filled with data from the assigned values. The data
* partial creates the "data" part for the JSON API response.
*
* The partial template files are usually stored in the templates/partials/ folder
* of the core or the extensions. The configured path to the partial file must
* be relative to the templates/ folder, e.g. "partials/data-standard.php".
*
* @param string Relative path to the template file
* @since 2016.07
* @category Developer
*/
$this->getView()->assign( array( 'partial-data' => 'admin/jsonadm/partials/locale/site/template-data' ) );
return parent::get( $request, $response );
}
/**
* Returns the items with parent/child relationships
*
* @param array $items List of items implementing \Aimeos\MShop\Common\Item\Iface
* @param array $include List of resource types that should be fetched
* @return array List of items implementing \Aimeos\MShop\Common\Item\Iface
*/
protected function getChildItems( array $items, array $include )
{
$list = [];
if( in_array( 'locale.site', $include ) )
{
foreach( $items as $item ) {
$list = array_merge( $list, [$item], $this->getChildItems( $item->getChildren(), $include ) );
}
}
return $list;
}
protected function getItems( \Aimeos\MW\View\Iface $view, ServerRequestInterface $request, ResponseInterface $response )
{
$manager = \Aimeos\MShop\Factory::createManager( $this->getContext(), 'locale/site' );
if( ( $key = $view->param( 'aggregate' ) ) !== null )
{
$search = $this->initCriteria( $manager->createSearch(), $view->param() );
$view->data = $manager->aggregate( $search, $key );
return $response;
}
$include = ( ( $include = $view->param( 'include' ) ) !== null ? explode( ',', $include ) : [] );
$search = $this->initCriteria( $manager->createSearch(), $view->param() );
$total = 1;
if( ( $id = $view->param( 'id' ) ) == null )
{
$view->data = $manager->searchItems( $search, [], $total );
$view->listItems = [];
$view->childItems = [];
}
else
{
$level = \Aimeos\MW\Tree\Manager\Base::LEVEL_ONE;
if( in_array( 'locale.site', $include ) ) {
$level = \Aimeos\MW\Tree\Manager\Base::LEVEL_LIST;
}
$view->data = $manager->getTree( $id, $include, $level, $search );
$view->listItems = [];
$view->childItems = $this->getChildItems( $view->data->getChildren(), $include );
}
$view->refItems = [];
$view->total = $total;
return $response;
}
/**
* Saves and returns the new or updated item
*
* @param \Aimeos\MShop\Common\Manager\Iface $manager Manager responsible for the items
* @param \stdClass $entry Object including "id" and "attributes" elements
* @return \Aimeos\MShop\Common\Item\Iface New or updated item
*/
protected function saveEntry( \Aimeos\MShop\Common\Manager\Iface $manager, \stdClass $entry )
{
$targetId = ( isset( $entry->targetid ) ? $entry->targetid : null );
$refId = ( isset( $entry->refid ) ? $entry->refid : null );
if( isset( $entry->id ) )
{
$item = $manager->getItem( $entry->id );
$item = $this->addItemData( $manager, $item, $entry, $item->getResourceType() );
$item = $manager->saveItem( $item );
if( isset( $entry->parentid ) && $targetId !== null ) {
$manager->moveItem( $item->getId(), $entry->parentid, $targetId, $refId );
}
}
else
{
$item = $manager->createItem();
$item = $this->addItemData( $manager, $item, $entry, $item->getResourceType() );
$manager->insertItem( $item );
}
if( isset( $entry->relationships ) ) {
$this->saveRelationships( $manager, $item, $entry->relationships );
}
return $manager->getItem( $item->getId() );
}
}
- Attachments
-
- Aimeos Tree Local Site.jpg (19.01 KiB) Viewed 203324 times
-
- Aimeos Tree Local Site - Item Create Update Delete.jpg (45.4 KiB) Viewed 203324 times
Last edited by tenkraD on 05 Dec 2018, 12:36, edited 1 time in total.
Re: Multiple Site 1 Basket / Checkout
The answer to post post7109.html#p7109 was, to get Both Products listed In aimeos backend on order page and invoice page, i modified the Locale. In locale manager class i added the childs in the $siteids that they are avaiable in the locale item class in the values $siteSubTree and $sitePath.
Manager
Path: ext/mhaimeos2018/Resources/Private/Extensions/mhaimeos2018/lib/custom/src/MShop/Locale/Manager/Sitesubtree.php
Item
Path: ext/mhaimeos2018/Resources/Private/Extensions/mhaimeos2018/lib/custom/src/MShop/Locale/Item/Sitesubtree.php
Manager
Path: ext/mhaimeos2018/Resources/Private/Extensions/mhaimeos2018/lib/custom/src/MShop/Locale/Manager/Sitesubtree.php
Code: Select all
<?php
/**
* @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
* @copyright Metaways Infosystems GmbH, 2011
* @copyright Aimeos (aimeos.org), 2015-2017
* @package MShop
* @subpackage Locale
*/
namespace Aimeos\MShop\Locale\Manager;
/**
* Extend the Default locale manager implementation.
* That Item/Sitesubtree can handle Subtrees
*
* @package MShop
* @subpackage Locale
*/
class Sitesubtree
extends Standard
implements \Aimeos\MShop\Locale\Manager\Iface, \Aimeos\MShop\Common\Manager\Factory\Iface
{
/**
* Instances a new locale item object.
*
* @param array $values Parameter to initialise the item
* @param \Aimeos\MShop\Locale\Item\Site\Iface|null $site Site item
* @param array $sitePath List of site IDs up to the root site
* @param array $siteSubTree List of site IDs below and including the current site
* @return \Aimeos\MShop\Locale\Item\Sitesubtree Locale item
*/
protected function createItemBase( array $values = [], \Aimeos\MShop\Locale\Item\Site\Iface $site = null,
array $sitePath = [], array $siteSubTree = [] )
{
return new \Aimeos\MShop\Locale\Item\Sitesubtree( $values, $site, $sitePath, $siteSubTree );
}
/**
* Returns the locale item for the given site code, language code and currency code.
*
* @param string $site Site code
* @param string $lang Language code (optional)
* @param string $currency Currency code (optional)
* @param boolean $active Flag to get only active items (optional)
* @param integer|null $level Constant from abstract class which site ID levels should be available (optional),
* based on config or value for SITE_PATH if null
* @param boolean $bare Allow locale items with sites only
* @return \Aimeos\MShop\Locale\Item\Iface Locale item for the given parameters
* @throws \Aimeos\MShop\Locale\Exception If no locale item is found
*/
public function bootstrap( $site, $lang = '', $currency = '', $active = true, $level = null, $bare = false )
{
$manager = $this->getObject()->getSubManager( 'site' );
$siteItem = $manager->findItem( $site );
// Get Tree with childs
$node = $manager->getTree($siteItem->getId());
$siteIds = array( );
if($node->hasChildren() == true) {
$childs = $this->getNodeMap( $node->getNode() );
$siteIds += $childs;
}else{
$siteIds = array( $siteItem->getId() );
}
return $this->bootstrapBase( $site, $lang, $currency, $active, $siteItem, $siteIds, $siteIds, $bare );
}
/**
* Creates a flat list node items.
*
* @param \Aimeos\MW\Tree\Node\Iface $node Root node
* @return array Associated list of ID
*/
protected function getNodeMap( \Aimeos\MW\Tree\Node\Iface $node)
{
$map = [];
$map[(string) $node->getId()] = (string) $node->getId();
foreach( $node->getChildren() as $child ) {
$map += $this->getNodeMap( $child );
}
return $map;
}
}
Path: ext/mhaimeos2018/Resources/Private/Extensions/mhaimeos2018/lib/custom/src/MShop/Locale/Item/Sitesubtree.php
Code: Select all
<?php
/**
* @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
* @copyright Metaways Infosystems GmbH, 2011
* @copyright Aimeos (aimeos.org), 2015-2017
* @package MShop
* @subpackage Locale
*/
namespace Aimeos\MShop\Locale\Item;
/**
* Common locale class containing the site, language and currency information.
*
* @package MShop
* @subpackage Locale
*/
class Sitesubtree
extends Standard
implements \Aimeos\MShop\Locale\Item\Iface
{
}
- Attachments
-
- Aimeos Tree Local Site Childs.jpg (96.33 KiB) Viewed 203324 times
Re: Multiple Site 1 Basket / Checkout
Hello Admin,
First question: How can i get the locale in my constructor, search, getPath(), getTree(), functions? in File /lib/custom/src/MShop/Locale/Manager/Site/standard.php
I try to get the locale there like this $this->getContext()->getLocale(); but its returning an exception "Locale object not available".
Second question: what do you think about my nodesites?
First question: How can i get the locale in my constructor, search, getPath(), getTree(), functions? in File /lib/custom/src/MShop/Locale/Manager/Site/standard.php
I try to get the locale there like this $this->getContext()->getLocale(); but its returning an exception "Locale object not available".
Second question: what do you think about my nodesites?
Re: Multiple Site 1 Basket / Checkout
The locale object isn't available in the managers of the locale domain because these managers must offer the bootstrap functionality to create a locale item.
Your implementation is good but reimplements a part of the extension from the Aimeos company
Your implementation is good but reimplements a part of the extension from the Aimeos company

Professional support and custom implementation are available at Aimeos.com
If you like Aimeos,
give us a star
If you like Aimeos,

Re: Multiple Site 1 Basket / Checkout
Got it.
My implementation has a lot of failures and fits just for my special case.
Use https://aimeos.com/extensions/ to get it work and to support aimeos.
I hope i was a good kid now
My implementation has a lot of failures and fits just for my special case.
Use https://aimeos.com/extensions/ to get it work and to support aimeos.
I hope i was a good kid now

Re: Multiple Site 1 Basket / Checkout
We appreciate all contributions to make Aimeos better 

Professional support and custom implementation are available at Aimeos.com
If you like Aimeos,
give us a star
If you like Aimeos,
