How to add additional fields to a customer

How to configure and adapt Aimeos based shops as developer
Forum rules
Always add your Aimeos and PHP version as well as your environment (Linux/Mac/Win)
Spam and unrelated posts will be removed immediately!
Post Reply
obayesshelton
Posts: 21
Joined: 12 Oct 2015, 12:31

How to add additional fields to a customer

Post by obayesshelton » 02 Feb 2016, 10:01

Hi,

Is it possible and if so how do I add a new property to a customer?

Thanks

User avatar
aimeos
Administrator
Posts: 7873
Joined: 01 Jan 1970, 00:00

Re: How to add additional fields to a customer

Post by aimeos » 02 Feb 2016, 11:10

You could either extend the user/customer table including the item and manager (inherit from the standard classes to save code) or you can reference attribute items via the list table if you need the data in the HTML client. The list reference items itself have a "config" field (stored as JSON) too.
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos, Image give us a star

mohal_04
Advanced
Posts: 108
Joined: 27 Mar 2018, 05:59

Re: How to add additional fields to a customer

Post by mohal_04 » 02 Apr 2018, 06:01

obayesshelton wrote:Hi,

Is it possible and if so how do I add a new property to a customer?

Thanks
Hi,

Were you able to extend customer class? I am stuck at extending product class but having difficulties. Can you look at my code and help me?

Item/Myproject.php:

Code: Select all

namespace Aimeos\MAdmin\Product\Item;
 
class Myproject extends Standard
{
    private $myvalues;
 
    public function __construct( array $values, ... )
    {
        parent::__construct( $values, ... )
        $this->myvalues = $values;
    }
 
    public function getMyId()
    {
        if( isset( $this->myvalues['myid'] ) ) {
            return (string) $this->myvalues['myid'];
        }
        return '';
    }
 
    public function setMyId( $val )
    {
        if( (string) $val !== $this->getMyId() )
        {
            $this->values['myid'] = (string) $myid;
            $this->setModified();
        }
        return $this;
    }
 
    public function fromArray( array $list )
    {
        $unknown = [];
        $list = parent::fromArray( $list );
 
        foreach( $list as $key => $value )
        {
            switch( $key )
            {
                case 'myid': $this->setMyId( $value ); break;
                default: $unknown[$key] = $value;
            }
        }
 
        return $unknown;
    }
 
    public function toArray( $private = false )
    {
        $list = parent::toArray( $private );
 
        if( $private === true ) {
            $list['myid'] = $this->getMyId();
        }
 
        return $list;
    }
}
Manager/Myproject.php

Code: Select all

namespace Aimeos\MAdmin\Product\Manager;
 
class Myproject extends Standard
{
    private $searchConfig = array(
        'product.oldcode'=> array(
            'code'=>'product.oldcode',
            'internalcode'=>'mpro."oldcode"',
            'label'=>'Product oldcode',
            'type'=> 'string', // integer, float, etc.
            'internaltype'=> \Aimeos\MW\DB\Statement\Base::PARAM_STR, // _INT, _FLOAT, etc.
        ),
    );
 
    public function saveItem( \Aimeos\MShop\Common\Item\Iface $item, $fetch = true )
    {
        // a modified copy of the code from the parent class
        // extended by a bind() call and updated bind positions (first parameter)
    }
 
    public function getSearchAttributes( $withsub = true )
    {
        $list = parent::getSearchAttributes( $withsub );
        foreach( $this->searchConfig as $key => $fields ) {
            $list[$key] = new \Aimeos\MW\Criteria\Attribute\Standard( $fields );
        }
        return $list;
    }
 
    protected function createItemBase( array $values = [] /* , ... */ )
    {
        return new \Aimeos\MShop\Product\Item\Myproject( $values /* , ... */ );
    }
}
This is the directory structure of my files:

./ext/10buckonly/lib/custom/src/MAdmin/Product/Item

Thanks!

User avatar
aimeos
Administrator
Posts: 7873
Joined: 01 Jan 1970, 00:00

Re: How to add additional fields to a customer

Post by aimeos » 03 Apr 2018, 07:47

You have to implement the saveItem() and createItemBase() methods by copying them from the Standard class and modify them accordingly for your new value. Also adapt the SQL statements for fetch and store the new value.
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos, Image give us a star

mohal_04
Advanced
Posts: 108
Joined: 27 Mar 2018, 05:59

Re: How to add additional fields to a customer

Post by mohal_04 » 03 Apr 2018, 09:36

aimeos wrote:You have to implement the saveItem() and createItemBase() methods by copying them from the Standard class and modify them accordingly for your new value. Also adapt the SQL statements for fetch and store the new value.
Hi,

I have rewritten my code 3 times and now the situation is this... I am able to display value in my extra field but it is not saving in the DB and there are no errors :(. Please, look at my code and guide me!

./ext/myextension/lib/custom/setup/default/schema/product.php

Code: Select all

return array(
	'table' => array(
		'mshop_product' => function ( \Doctrine\DBAL\Schema\Schema $schema ) {

			// $table = $schema->createTable( 'mshop_price' );
			$table = $schema->getTable( 'mshop_product' );

			$table->addColumn( 'oldcode', 'string', array( 'length' => 32 ) );

			$table->addIndex( array( 'siteid', 'oldcode' ), 'idx_msproty_sid_oldcode' );

			return $schema;
		}
	)
);
./ext/myextension/lib/custom/src/MShop/Product/Item/Myproject.php

Code: Select all

namespace Aimeos\MShop\Product\Item;
 
class Myproject extends Standard
{
    private $myvalues;
 
    public function __construct(array $values)
    {
        parent::__construct($values);
        $this->myvalues = $values;
    }
 
    public function getOldCode()
    {
        if( isset( $this->myvalues['product.oldcode'] ) ) {
            return (string) $this->myvalues['product.oldcode'];
        }
        return '';
    }
 
    public function setOldCode( $oldcode )
    {
        if ((string) $oldcode !== $this->getOldCode()) {
            // exit("<br />616");
            $this->myvalues['product.oldcode'] = (string) $oldcode;
            $this->setModified();
        }
        return $this;
    }
 
    public function fromArray(array $list)
    {
        $unknown = [];
        $list = parent::fromArray($list);

        foreach ($list as $key => $value) {
            switch ($key) {
                case 'product.oldcode':
                    $this->setOldCode($value);
                    break;
                default:
                    $unknown[$key] = $value;
            }
        }
        // exit("<br />617");
        return $unknown;
    }
 
    public function toArray( $private = false )
    {
        $list = parent::toArray( $private );
 
        if( $private === true ) {
            $list['product.oldcode'] = $this->getOldCode();
        }
 
        return $list;
    }
}
./ext/myextension/lib/custom/src/MShop/Product/Manager/Myproject.php

Code: Select all

namespace Aimeos\MShop\Product\Manager;
 
class Myproject extends Standard
{
    private $searchConfig = array(
        'product.oldcode'=> array(
            'code'=>'product.oldcode',
            'internalcode'=>'mpro."oldcode"',
            'label'=>'Product oldcode',
            'type'=> 'string', // integer, float, etc.
            'internaltype'=> \Aimeos\MW\DB\Statement\Base::PARAM_STR, // _INT, _FLOAT, etc.
        ),
    );
 
    public function saveItem(\Aimeos\MShop\Common\Item\Iface $item, $fetch = true)
    {
        $iface = '\\Aimeos\\MShop\\Product\\Item\\Iface';
        if (! ($item instanceof $iface)) {
            throw new \Aimeos\MShop\Product\Exception(sprintf('Object is not of required type "%1$s"', $iface));
        }

        if (!$item->isModified()) {
            return $item;
        }

        $context = $this->getContext();

        $dbm = $context->getDatabaseManager();
        $dbname = $this->getResourceName();
        $conn = $dbm->acquire( $dbname );

        try {
            $id = $item->getId();
            $date = date('Y-m-d H:i:s');
            if ($id === null) {
                $path = 'mshop/product/manager/standard/insert';
            } else {
                $path = 'mshop/product/manager/standard/update';
            }
            $stmt = $this->getCachedStatement($conn, $path);

            $stmt->bind(1, $item->getTypeId(), \Aimeos\MW\DB\Statement\Base::PARAM_INT);
            $stmt->bind(2, $context->getLocale()->getSiteId(), \Aimeos\MW\DB\Statement\Base::PARAM_INT);
            $stmt->bind(3, $item->getCode());
            $stmt->bind(4, $item->getLabel());
            $stmt->bind(5, json_encode($item->getConfig()));
            $stmt->bind(6, $item->getDateStart());
            $stmt->bind(7, $item->getDateEnd());
            $stmt->bind(8, $item->getStatus(), \Aimeos\MW\DB\Statement\Base::PARAM_INT);
            $stmt->bind(9, $date); // mtime
            $stmt->bind(10, $context->getEditor());
            $stmt->bind(11, $item->getTarget());
            $stmt->bind(12, $item->getOldCode());

            if( $id !== null ) {
                $stmt->bind( 13, $id, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
                $item->setId( $id ); //so item is no longer modified
            } else {
                $stmt->bind( 13, $date ); // ctime
            }

            $stmt->execute()->finish();

            if( $id === null && $fetch === true )
            {
                $path = 'mshop/product/manager/standard/newid';
                $item->setId( $this->newId( $conn, $path ) );
            }

            $dbm->release( $conn, $dbname );

        } catch (\Exception $e) {
            $dbm->release( $conn, $dbname );
            throw $e;
        }
        return $item;
    }
 
    public function getSearchAttributes( $withsub = true )
    {
        $list = parent::getSearchAttributes( $withsub );
        foreach( $this->searchConfig as $key => $fields ) {
            $list[$key] = new \Aimeos\MW\Criteria\Attribute\Standard( $fields );
        }
        return $list;
    }
 
    protected function createItemBase(array $values = [], array $listitems = [],
        array $refItems = [], array $propertyItems = [])
    {
        return new \Aimeos\MShop\Product\Item\Myproject($values, $listitems, $refItems, $propertyItems);
    }
}
and

./ext/myextension/lib/custom/config/mshop.php

Code: Select all

return [
    'product' => [
        'manager' => [
            'name' => 'Myproject',
            'standard' => [
				'insert' => array(
					'ansi' => '
						INSERT INTO "mshop_product" (
							"typeid", "siteid", "code", "label", "config", "start", "end",
							"status", "mtime", "editor", "target", "ctime", "oldcode"
						) VALUES (
							?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
						)
					'
				),
				'update' => array(
					'ansi' => '
						UPDATE "mshop_product"
						SET "typeid" = ?, "code" = ?, "label" = ?, "status" = ?,
							"start" = ?, "end" = ?, "config" = ?, "mtime" = ?, "editor" = ?, "target" = ?, "oldcode" = ?
						WHERE "siteid" = ? AND "id" = ?
					'
				),
				'search' => array(
					'ansi' => '
						SELECT mpro."id" AS "product.id", mpro."siteid" AS "product.siteid",
							mpro."typeid" AS "product.typeid", mpro."code" AS "product.code",
							mpro."label" AS "product.label", mpro."config" AS "product.config",
							mpro."start" AS "product.datestart", mpro."end" AS "product.dateend",
							mpro."status" AS "product.status", mpro."ctime" AS "product.ctime",
							mpro."mtime" AS "product.mtime", mpro."editor" AS "product.editor",
							mpro."target" AS "product.target",
							mpro."oldcode" AS "product.oldcode"
						FROM "mshop_product" AS mpro
						:joins
						WHERE :cond
						GROUP BY mpro."id", mpro."siteid", mpro."typeid", mpro."code",
							mpro."label", mpro."config", mpro."start", mpro."end",
							mpro."status", mpro."ctime", mpro."mtime", mpro."editor",
							mpro."target", mpro."oldcode"
							/*-columns*/ , :columns /*columns-*/
						/*-orderby*/ ORDER BY :order /*orderby-*/
						LIMIT :size OFFSET :start
					'
				),
				'count' => array(
					'ansi' => '
						SELECT COUNT(*) AS "count"
						FROM (
							SELECT DISTINCT mpro."id"
							FROM "mshop_product" AS mpro
							:joins
							WHERE :cond
							LIMIT 10000 OFFSET 0
						) AS list
					'
				),
				'newid' => array(
					'db2' => 'SELECT IDENTITY_VAL_LOCAL()',
					'mysql' => 'SELECT LAST_INSERT_ID()',
					'oracle' => 'SELECT mshop_product_seq.CURRVAL FROM DUAL',
					'pgsql' => 'SELECT lastval()',
					'sqlite' => 'SELECT last_insert_rowid()',
					'sqlsrv' => 'SELECT SCOPE_IDENTITY()',
					'sqlanywhere' => 'SELECT @@IDENTITY',
				),
            ],
        ],
    ],
];
Everything seems fine but still I am unable to save value for my custom field, i.e. oldcode.

Thanks!

mohal_04
Advanced
Posts: 108
Joined: 27 Mar 2018, 05:59

Re: How to add additional fields to a customer

Post by mohal_04 » 03 Apr 2018, 11:49

Finally, I have done it! Thanks to Almighty Allah! Writing my full code here for others like me.

./ext/myextension/lib/custom/setup/default/schema/product.php

Code: Select all

return array(
	'table' => array(
		'mshop_product' => function ( \Doctrine\DBAL\Schema\Schema $schema ) {

			// $table = $schema->createTable( 'mshop_price' );
			$table = $schema->getTable( 'mshop_product' );

			$table->addColumn( 'oldcode', 'string', array( 'length' => 32 ) );

			$table->addIndex( array( 'siteid', 'oldcode' ), 'idx_msproty_sid_oldcode' );

			return $schema;
		}
	)
);
./ext/myextension/lib/custom/src/MShop/Product/Item/Myproject.php

Code: Select all

namespace Aimeos\MShop\Product\Item;
 
class Myproject extends Standard
{
    private $myvalues;
 
    public function __construct(array $values)
    {
        parent::__construct($values);
        $this->myvalues = $values;
    }
 
    public function getOldCode()
    {
        if( isset( $this->myvalues['product.oldcode'] ) ) {
            return (string) $this->myvalues['product.oldcode'];
        }
        return '';
    }
 
    public function setOldCode( $oldcode )
    {
        if ((string) $oldcode !== $this->getOldCode()) {
            // exit("<br />616");
            $this->myvalues['product.oldcode'] = (string) $oldcode;
            $this->setModified();
        }
        return $this;
    }
 
    public function fromArray(array $list)
    {
        $unknown = [];
        $list = parent::fromArray($list);

        foreach ($list as $key => $value) {
            switch ($key) {
                case 'product.oldcode':
                    $this->setOldCode($value);
                    break;
                default:
                    $unknown[$key] = $value;
            }
        }
        // exit("<br />617");
        return $unknown;
    }
 
    public function toArray( $private = false )
    {
        $list = parent::toArray( $private );
 
        if( $private === true ) {
            $list['product.oldcode'] = $this->getOldCode();
        }
 
        return $list;
    }
}
./ext/myextension/lib/custom/src/MShop/Product/Manager/Myproject.php

Code: Select all

namespace Aimeos\MShop\Product\Manager;
 
class Myproject extends Standard
{
    private $searchConfig = array(
        'product.oldcode'=> array(
            'code'=>'product.oldcode',
            'internalcode'=>'mpro."oldcode"',
            'label'=>'Product oldcode',
            'type'=> 'string', // integer, float, etc.
            'internaltype'=> \Aimeos\MW\DB\Statement\Base::PARAM_STR, // _INT, _FLOAT, etc.
        ),
    );
 
    public function saveItem(\Aimeos\MShop\Common\Item\Iface $item, $fetch = true)
    {
        $iface = '\\Aimeos\\MShop\\Product\\Item\\Iface';
        if (! ($item instanceof $iface)) {
            throw new \Aimeos\MShop\Product\Exception(sprintf('Object is not of required type "%1$s"', $iface));
        }

        if (!$item->isModified()) {
            return $item;
        }

        $context = $this->getContext();

        $dbm = $context->getDatabaseManager();
        $dbname = $this->getResourceName();
        $conn = $dbm->acquire( $dbname );

        try {
            $id = $item->getId();
            $date = date('Y-m-d H:i:s');
            if ($id === null) {
                $path = 'mshop/product/manager/standard/insert';
            } else {
                $path = 'mshop/product/manager/standard/update';
            }
            $stmt = $this->getCachedStatement($conn, $path);

            $stmt->bind(1, $item->getOldCode());
            $stmt->bind( 2, $item->getTypeId(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
            $stmt->bind( 3, $item->getCode() );
            $stmt->bind( 4, $item->getLabel() );
            $stmt->bind( 5, $item->getStatus(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
            $stmt->bind( 6, $item->getDateStart() );
            $stmt->bind( 7, $item->getDateEnd() );
            $stmt->bind( 8, json_encode( $item->getConfig() ) );
            $stmt->bind( 9, $date ); // mtime
            $stmt->bind( 10, $context->getEditor() );
            $stmt->bind( 11, $item->getTarget() );
            $stmt->bind( 12, $context->getLocale()->getSiteId(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );

            if( $id !== null ) {
                $stmt->bind( 13, $id, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
                $item->setId( $id ); //so item is no longer modified
            } else {
                $stmt->bind( 13, $date ); // ctime
            }
            $stmt->execute()->finish();
            if( $id === null && $fetch === true )
            {
                $path = 'mshop/product/manager/standard/newid';
                $item->setId( $this->newId( $conn, $path ) );
            }

            $dbm->release( $conn, $dbname );
        } catch (\Exception $e) {
            $dbm->release( $conn, $dbname );
            throw $e;
        }
        return $item;
    }
 
    public function getSearchAttributes( $withsub = true )
    {
        $list = parent::getSearchAttributes( $withsub );
        foreach( $this->searchConfig as $key => $fields ) {
            $list[$key] = new \Aimeos\MW\Criteria\Attribute\Standard( $fields );
        }
        return $list;
    }
 
    protected function createItemBase(array $values = [], array $listitems = [],
        array $refItems = [], array $propertyItems = [])
    {
        return new \Aimeos\MShop\Product\Item\Myproject($values, $listitems, $refItems, $propertyItems);
    }
}
and

./ext/myextension/lib/custom/config/mshop.php

Code: Select all

return [
    'product' => [
        'manager' => [
            'name' => 'Myproject',
            'standard' => [
				'insert' => array(
					'ansi' => '
						INSERT INTO "mshop_product" (
							"oldcode", "typeid", "code", "label", "status", "start", "end",
							"config", "mtime", "editor", "target", "siteid", "ctime"
						) VALUES (
							?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
						)
					'
				),
				'update' => array(
					'ansi' => '
						UPDATE "mshop_product"
						SET "oldcode" = ?, "typeid" = ?, "code" = ?, "label" = ?, "status" = ?,
							"start" = ?, "end" = ?, "config" = ?, "mtime" = ?, "editor" = ?, "target" = ?
						WHERE "siteid" = ? AND "id" = ?
					'
				),
				'search' => array(
					'ansi' => '
						SELECT mpro."id" AS "product.id", mpro."siteid" AS "product.siteid",
							mpro."typeid" AS "product.typeid", mpro."code" AS "product.code",
							mpro."label" AS "product.label", mpro."config" AS "product.config",
							mpro."start" AS "product.datestart", mpro."end" AS "product.dateend",
							mpro."status" AS "product.status", mpro."ctime" AS "product.ctime",
							mpro."mtime" AS "product.mtime", mpro."editor" AS "product.editor",
							mpro."target" AS "product.target",
							mpro."oldcode" AS "product.oldcode"
						FROM "mshop_product" AS mpro
						:joins
						WHERE :cond
						GROUP BY mpro."id", mpro."siteid", mpro."typeid", mpro."code",
							mpro."label", mpro."config", mpro."start", mpro."end",
							mpro."status", mpro."ctime", mpro."mtime", mpro."editor",
							mpro."target", mpro."oldcode"
							/*-columns*/ , :columns /*columns-*/
						/*-orderby*/ ORDER BY :order /*orderby-*/
						LIMIT :size OFFSET :start
					'
				),
				'count' => array(
					'ansi' => '
						SELECT COUNT(*) AS "count"
						FROM (
							SELECT DISTINCT mpro."id"
							FROM "mshop_product" AS mpro
							:joins
							WHERE :cond
							LIMIT 10000 OFFSET 0
						) AS list
					'
				),
				'newid' => array(
					'db2' => 'SELECT IDENTITY_VAL_LOCAL()',
					'mysql' => 'SELECT LAST_INSERT_ID()',
					'oracle' => 'SELECT mshop_product_seq.CURRVAL FROM DUAL',
					'pgsql' => 'SELECT lastval()',
					'sqlite' => 'SELECT last_insert_rowid()',
					'sqlsrv' => 'SELECT SCOPE_IDENTITY()',
					'sqlanywhere' => 'SELECT @@IDENTITY',
				),
            ],
        ],
    ],
];
OK now trick here is to keep your field at the first position. Official documentation also has it mentioned but I learned it the hard way.
public function saveItem( \Aimeos\MShop\Common\Item\Iface $item, $fetch = true )
{
// a modified copy of the code from the parent class
// extended by a bind() call and updated bind positions (first parameter)
}
So, as you can see me Manager class and configuration file, I have "oldcode" at the first position. The position does matter.

Code: Select all

$stmt->bind(1, $item->getOldCode());
            $stmt->bind( 2, $item->getTypeId(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
            $stmt->bind( 3, $item->getCode() );
            $stmt->bind( 4, $item->getLabel() );
            $stmt->bind( 5, $item->getStatus(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
            $stmt->bind( 6, $item->getDateStart() );
            $stmt->bind( 7, $item->getDateEnd() );
            $stmt->bind( 8, json_encode( $item->getConfig() ) );
            $stmt->bind( 9, $date ); // mtime
            $stmt->bind( 10, $context->getEditor() );
            $stmt->bind( 11, $item->getTarget() );
            $stmt->bind( 12, $context->getLocale()->getSiteId(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );

Code: Select all

'insert' => array(
					'ansi' => '
						INSERT INTO "mshop_product" (
							"oldcode", "typeid", "code", "label", "status", "start", "end",
							"config", "mtime", "editor", "target", "siteid", "ctime"
						) VALUES (
							?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
						)
					'
				),
				'update' => array(
					'ansi' => '
						UPDATE "mshop_product"
						SET "oldcode" = ?, "typeid" = ?, "code" = ?, "label" = ?, "status" = ?,
							"start" = ?, "end" = ?, "config" = ?, "mtime" = ?, "editor" = ?, "target" = ?
						WHERE "siteid" = ? AND "id" = ?
					'
				),
Thanks!

User avatar
aimeos
Administrator
Posts: 7873
Joined: 01 Jan 1970, 00:00

Re: How to add additional fields to a customer

Post by aimeos » 04 Apr 2018, 22:07

The __construct() method of your product item is wrong because it doesn't accept the list items, ref items and property items you pass in createItemBase() of your manager. These data also have to be passed to the parent constructor in your product item class (parent::__construct( $values, $listItems, ... ))
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos, Image give us a star

mohal_04
Advanced
Posts: 108
Joined: 27 Mar 2018, 05:59

Re: How to add additional fields to a customer

Post by mohal_04 » 05 Apr 2018, 06:23

aimeos wrote:The __construct() method of your product item is wrong because it doesn't accept the list items, ref items and property items you pass in createItemBase() of your manager. These data also have to be passed to the parent constructor in your product item class (parent::__construct( $values, $listItems, ... ))
Thank you buddy! You saved my day!!! I almost pulled out all my hairs :)

I posted my question here post5945.html#p5945 also.

It was due to same reason.

Thanks!

mohal_04
Advanced
Posts: 108
Joined: 27 Mar 2018, 05:59

Re: How to add additional fields to a customer

Post by mohal_04 » 06 Apr 2018, 03:05

aimeos wrote:The __construct() method of your product item is wrong because it doesn't accept the list items, ref items and property items you pass in createItemBase() of your manager. These data also have to be passed to the parent constructor in your product item class (parent::__construct( $values, $listItems, ... ))
Hi,

I am tired of Aimeos Laravel Package. Daily I have to fix a new issue! Anyhow, the problem now I am facing is that... I created an extension and followed this https://aimeos.org/docs/Developers/Libr ... gers_items document to extend Item and Manager, to add an extra field in Basic section. See screen-shot below:
Old SKU field
Old SKU field
new_field.jpg (62.97 KiB) Viewed 7527 times
It took me few days to figure out the whole thing but it is working fine now. Next, I want to do the same with Price section of Product edit form. I want to add "Minimum Advertised Price" field to Price section. See screen-shot below:
Min Ads Price
Min Ads Price
ma_price.jpg (88.08 KiB) Viewed 7527 times
And I thought the steps for this are also same. So, here is my code (after code, I have described my problem).

Item Class
./ext/myext/lib/custom/src/MShop/Price/Item/Custompricefields.php

Code: Select all

namespace Aimeos\MShop\Price\Item;
 
class Custompricefields extends Standard
{
    private $myvalues;
 
    public function __construct(array $values, array $listItems, array $refItems)
    {
        parent::__construct($values, $listItems, $refItems);
        $this->myvalues = $values;
    }
 
    public function getMinimumAdvertisedPrice()
    {
        if (isset($this->myvalues['price.minimumadvertisedprice'])) {
            return (string) $this->myvalues['price.minimumadvertisedprice'];
        }
        return '';
    }
 
    public function setMinimumAdvertisedPrice($minimumadvertisedprice)
    {
        if ((string) $minimumadvertisedprice !== $this->getMinimumAdvertisedPrice()) {
            $this->myvalues['price.minimumadvertisedprice'] = (string) $minimumadvertisedprice;
            $this->setModified();
        }
        return $this;
    }
 
    public function fromArray(array $list)
    {
        $unknown = [];
        $list = parent::fromArray($list);

        foreach ($list as $key => $value) {
            switch ($key) {
                case 'price.minimumadvertisedprice':
                    $this->setMinimumAdvertisedPrice($value);
                    break;
                default:
                    $unknown[$key] = $value;
            }
        }
        return $unknown;
    }
 
    public function toArray($private = false)
    {
        $list = parent::toArray($private);
        if ($private === true) {
            $list['price.minimumadvertisedprice'] = $this->getMinimumAdvertisedPrice();
        }
        return $list;
    }
}
Manager Class
./ext/myext/lib/custom/src/MShop/Price/Manager/Custompricefields.php

Code: Select all

namespace Aimeos\MShop\Price\Manager;
 
class Custompricefields extends Standard
{
    private $searchConfig = array(
        'price.minimumadvertisedprice' => array(
            'code' => 'price.minimumadvertisedprice',
            'internalcode' => 'mpri."minimumadvertisedprice"',
            'label' => 'Minimum Advertised Price',
            'type' => 'float', // integer, string, etc.
            'internaltype' => \Aimeos\MW\DB\Statement\Base::PARAM_FLOAT, // _INT, _STR, etc.
        )
    );
 
    public function saveItem(\Aimeos\MShop\Common\Item\Iface $item, $fetch = true)
    {
        $iface = '\\Aimeos\\MShop\\Price\\Item\\Iface';
        if( !( $item instanceof $iface ) ) {
            throw new \Aimeos\MShop\Price\Exception( sprintf( 'Object is not of required type "%1$s"', $iface ) );
        }

        if( !$item->isModified() ) {
            return $item;
        }

        $context = $this->getContext();

        $dbm = $context->getDatabaseManager();
        $dbname = $this->getResourceName();
        $conn = $dbm->acquire( $dbname );

        try
        {
            $id = $item->getId();
            $date = date( 'Y-m-d H:i:s' );

            if ($id === null) {
                $path = 'mshop/price/manager/standard/insert';
            } else {
                $path = 'mshop/price/manager/standard/update';
            }

            $stmt = $this->getCachedStatement($conn, $path);

            $stmt->bind(1, $item->getMinimumAdvertisedPrice());
            $stmt->bind(2, $item->getTypeId(), \Aimeos\MW\DB\Statement\Base::PARAM_INT);
            $stmt->bind(3, $item->getCurrencyId());
            $stmt->bind(4, $item->getDomain());
            $stmt->bind(5, $item->getLabel());
            $stmt->bind(6, $item->getQuantity(), \Aimeos\MW\DB\Statement\Base::PARAM_INT);
            $stmt->bind(7, $item->getValue());
            $stmt->bind(8, $item->getCosts());
            $stmt->bind(9, $item->getRebate());
            $stmt->bind(10, $item->getTaxRate());
            $stmt->bind(11, $item->getStatus(), \Aimeos\MW\DB\Statement\Base::PARAM_INT);
            $stmt->bind(12, $date); //mtime
            $stmt->bind(13, $context->getEditor());
            $stmt->bind(14, $context->getLocale()->getSiteId(), \Aimeos\MW\DB\Statement\Base::PARAM_INT);
            if ($id !== null) {
                $stmt->bind(15, $id, \Aimeos\MW\DB\Statement\Base::PARAM_INT);
                $item->setId($id);
            } else {
                $stmt->bind(15, $date); //ctime
            }
            $stmt->execute()->finish();
            if ($id === null && $fetch === true) {
                $path = 'mshop/price/manager/standard/newid';
                $item->setId($this->newId($conn, $path));
            }
            $dbm->release($conn, $dbname);
        } catch(\Exception $e) {
            $dbm->release($conn, $dbname);
            throw $e;
        }
        return $item;
    }
 
    public function getSearchAttributes($withsub = true)
    {
        $list = parent::getSearchAttributes($withsub);
        foreach ($this->searchConfig as $key => $fields) {
            $list[$key] = new \Aimeos\MW\Criteria\Attribute\Standard($fields);
        }
        return $list;
    }
 
    protected function createItemBase(array $values = [], array $listitems = [], array $refItems = [])
    {
        return new \Aimeos\MShop\Price\Item\Custompricefields($values, $listitems, $refItems);
    }
}

And configuration file:

./ext/myext/lib/custom/config/mshop.php

Code: Select all

return [
    'product' => [
        'manager' => [
            'name' => 'Myproject',
            'standard' => [
				'insert' => array(
					'ansi' => '
						INSERT INTO "mshop_product" (
							"countryoforigin", "oldcode", "typeid", "code", "label", "status", "start", "end",
							"config", "mtime", "editor", "target", "siteid", "ctime"
						) VALUES (
							?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
						)
					'
				),
				'update' => array(
					'ansi' => '
						UPDATE "mshop_product"
						SET "countryoforigin" = ?, "oldcode" = ?, "typeid" = ?, "code" = ?, "label" = ?, "status" = ?,
							"start" = ?, "end" = ?, "config" = ?, "mtime" = ?, "editor" = ?, "target" = ?
						WHERE "siteid" = ? AND "id" = ?
					'
				),
				'search' => array(
					'ansi' => '
						SELECT mpro."id" AS "product.id", mpro."siteid" AS "product.siteid",
							mpro."typeid" AS "product.typeid", mpro."code" AS "product.code",
							mpro."label" AS "product.label", mpro."config" AS "product.config",
							mpro."start" AS "product.datestart", mpro."end" AS "product.dateend",
							mpro."status" AS "product.status", mpro."ctime" AS "product.ctime",
							mpro."mtime" AS "product.mtime", mpro."editor" AS "product.editor",
							mpro."target" AS "product.target",
							mpro."oldcode" AS "product.oldcode",
							mpro."countryoforigin" AS "product.countryoforigin"
						FROM "mshop_product" AS mpro
						:joins
						WHERE :cond
						GROUP BY mpro."id", mpro."siteid", mpro."typeid", mpro."code",
							mpro."label", mpro."config", mpro."start", mpro."end",
							mpro."status", mpro."ctime", mpro."mtime", mpro."editor",
							mpro."target", mpro."oldcode", mpro."countryoforigin"
							/*-columns*/ , :columns /*columns-*/
						/*-orderby*/ ORDER BY :order /*orderby-*/
						LIMIT :size OFFSET :start
					'
				),
				'count' => array(
					'ansi' => '
						SELECT COUNT(*) AS "count"
						FROM (
							SELECT DISTINCT mpro."id"
							FROM "mshop_product" AS mpro
							:joins
							WHERE :cond
							LIMIT 10000 OFFSET 0
						) AS list
					'
				),
				'newid' => array(
					'db2' => 'SELECT IDENTITY_VAL_LOCAL()',
					'mysql' => 'SELECT LAST_INSERT_ID()',
					'oracle' => 'SELECT mshop_product_seq.CURRVAL FROM DUAL',
					'pgsql' => 'SELECT lastval()',
					'sqlite' => 'SELECT last_insert_rowid()',
					'sqlsrv' => 'SELECT SCOPE_IDENTITY()',
					'sqlanywhere' => 'SELECT @@IDENTITY',
				),
            ],
        ],
    ],
    'price' => [
        'manager' => [
            'name' => 'Custompricefields',
            'standard' => [
				'insert' => array(
					'ansi' => '
						INSERT INTO "mshop_price" (
							"minimumadvertisedprice", "typeid", "currencyid", "domain", "label",
							"quantity", "value", "costs", "rebate", "taxrate",
							"status", "mtime", "editor", "siteid", "ctime"
						) VALUES (
							?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
						)
					'
				),
				'update' => array(
					'ansi' => '
						UPDATE "mshop_price"
						SET "minimumadvertisedprice" = ?, "typeid" = ?, "currencyid" = ?, "domain" = ?, "label" = ?,
							"quantity" = ?, "value" = ?, "costs" = ?, "rebate" = ?,
							"taxrate" = ?, "status" = ?, "mtime" = ?, "editor" = ?
						WHERE "siteid" = ? AND "id" = ?
					'
				),
				'search' => array(
					'ansi' => '
						SELECT mpri."id" AS "price.id", mpri."siteid" AS "price.siteid",
							mpri."typeid" AS "price.typeid", mpri."currencyid" AS "price.currencyid",
							mpri."domain" AS "price.domain", mpri."label" AS "price.label",
							mpri."quantity" AS "price.quantity", mpri."value" AS "price.value",
							mpri."costs" AS "price.costs", mpri."rebate" AS "price.rebate",
							mpri."taxrate" AS "price.taxrate", mpri."status" AS "price.status",
							mpri."mtime" AS "price.mtime", mpri."editor" AS "price.editor",
							mpri."ctime" AS "price.ctime",
							mpri."minimumadvertisedprice" AS "price.minimumadvertisedprice"
						FROM "mshop_price" AS mpri
						:joins
						WHERE :cond
						GROUP BY mpri."id", mpri."siteid", mpri."typeid", mpri."currencyid",
							mpri."domain", mpri."label", mpri."quantity", mpri."value",
							mpri."costs", mpri."rebate", mpri."taxrate", mpri."status",
							mpri."mtime", mpri."editor", mpri."ctime", mpri."minimumadvertisedprice" /*-columns*/ , :columns /*columns-*/
						/*-orderby*/ ORDER BY :order /*orderby-*/
						LIMIT :size OFFSET :start
					'
				),
				'count' => array(
					'ansi' => '
						SELECT COUNT(*) AS "count"
						FROM (
							SELECT DISTINCT mpri."id"
							FROM "mshop_price" AS mpri
							:joins
							WHERE :cond
							LIMIT 10000 OFFSET 0
						) AS list
					'
				),
				'newid' => array(
					'db2' => 'SELECT IDENTITY_VAL_LOCAL()',
					'mysql' => 'SELECT LAST_INSERT_ID()',
					'oracle' => 'SELECT mshop_price_seq.CURRVAL FROM DUAL',
					'pgsql' => 'SELECT lastval()',
					'sqlite' => 'SELECT last_insert_rowid()',
					'sqlsrv' => 'SELECT SCOPE_IDENTITY()',
					'sqlanywhere' => 'SELECT @@IDENTITY',
				),
            ],
        ],
    ],
];
That was all the code. Now, the problem is this that nothing happens. Value of my "Old SKU" field is saving and showing but value of "Minimum Advertised Price" field is neither saving nor showing. I am under the impression that Aimeos Package is not even registering/reading my second Manager, i.e. "Custompricefields."

Can you go through my code and see what am I doing wrong? Do I have to create separate configuration file for Price Section? BTW, I did make a separate file name "iprice.php" inside "config" directory but still same issue.

Please, help! I tried to explain my problem as much as I could but still if you need to check other stuff in the code then let me know.

Thanks!

User avatar
aimeos
Administrator
Posts: 7873
Joined: 01 Jan 1970, 00:00

Re: How to add additional fields to a customer

Post by aimeos » 06 Apr 2018, 08:49

The problem is most probably that the price panel is using Vue.JS to render the data and you have to extend the JS code too to get it working: https://github.com/aimeos/ai-admin-jqad ... ux.js#L264
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos, Image give us a star

Post Reply