site form - update attributes table

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!
khizar
Posts: 99
Joined: 19 Jan 2021, 09:51

site form - update attributes table

Post by khizar » 01 Feb 2021, 11:22

hy guys,
i have integrated aimeos with laravel 8.i was given a task to add a custom field in my site form which i achived successfully
by adding my own manager and item classes.
now when i add new site the attributes table is empty for newly created site
Image

but when create a new site using command
line (php artisan aimeos:setup mysite)
there are some builtin attributes for site
Image

now i want to also add those attributes when i make a site through form.
To acheive this i added the following code in insertItem method of my manager class in my extension

Code: Select all

	$context = $this->getContext();

		$dbm = $context->getDatabaseManager();
        $dbname = $this->getResourceName();
        
        $conn = $dbm->acquire( $dbname );
        try{
            
            $cmd = "aimeos:setup mysite";
       
         $output = Artisan::call($cmd);
        

        $dbm->release( $conn);
        }
        catch( Exception $e )
        {
	    $dbm->release( $conn );
	    throw $e;
        }
but when i tried to create new site an error appeared
Maximum number of connections (3) for "db" exceeded aimeos
so i also increased the maximum number of connections to 500 but it also exceeded.
below is my normal manager class which i used to store data normally which works fine but as i described above i
want to update attributes table also after making new site

Code: Select all

<?php
namespace Aimeos\MShop\Locale\Manager\Site;

use Illuminate\Support\Facades\Artisan;

class Myproject extends Standard
{
    private $searchConfig = array(
        'locale.site.city'=> array(
            'code'=>'locale.site.city',
            'internalcode'=>'mlocsi."city"',
            'label'=>'Product oldcode',
            'type'=> 'string', // integer, float, etc.
            'internaltype'=> \Aimeos\MW\DB\Statement\Base::PARAM_STR, // _INT, _FLOAT, etc.
        ),
    );


 
    public function saveItem( \Aimeos\MShop\Locale\Item\Site\Iface $item, bool $fetch = true ) : \Aimeos\MShop\Locale\Item\Site\Iface
	{   
       
		if( $item->getId() === null ) {
			throw new \Aimeos\MShop\Locale\Exception( sprintf( 'Newly created site can not be saved using method "saveItem()". Try using method "insertItem()" instead.' ) );
		}

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

		$context = $this->getContext();

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

		try
		{
			$id = $item->getId();
			$columns = $this->getObject()->getSaveAttributes();

			/** mshop/locale/manager/site/standard/update/mysql
			 * Updates an existing site record in the database
			 *
			 * @see mshop/locale/manager/site/standard/update/ansi
			 */

			/** mshop/locale/manager/site/standard/update/ansi
			 * Updates an existing site record 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 site item to the statement before they are
			 * sent to the database server. The order of the columns must
			 * correspond to the order in the saveItems() 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/insert/ansi
			 * @see mshop/locale/manager/site/standard/delete/ansi
			 * @see mshop/locale/manager/site/standard/search/ansi
			 * @see mshop/locale/manager/site/standard/count/ansi
			 * @see mshop/locale/manager/site/standard/newid/ansi
			 */
			$path = 'mshop/locale/manager/site/standard/update';
			$sql = $this->addSqlColumns( array_keys( $columns ), $this->getSqlConfig( $path ), false );

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

			foreach( $columns as $name => $entry ) {
				$stmt->bind( $idx++, $item->get( $name ), $entry->getInternalType() );
			}

            $stmt->bind( $idx++, $item->getCity() );
            $stmt->bind( $idx++, $item->getSiteId() );
			$stmt->bind( $idx++, $item->getCode() );
			$stmt->bind( $idx++, $item->getLabel() );
			$stmt->bind( $idx++, json_encode( $item->getConfig() ) );
			$stmt->bind( $idx++, $item->getStatus(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
			$stmt->bind( $idx++, $context->getEditor() );
			$stmt->bind( $idx++, date( 'Y-m-d H:i:s' ) ); // mtime
			$stmt->bind( $idx++, $id, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
          
			$stmt->execute()->finish();
			$item->setId( $id ); // set Modified false

			$dbm->release( $conn, $dbname );
		}
		catch( \Exception $e )
		{
			$dbm->release( $conn, $dbname );
			throw $e;
		}

		return $item;
	}

    
    public function insertItem( \Aimeos\MShop\Locale\Item\Site\Iface $item, string $parentId = null, string $refId = null ) : \Aimeos\MShop\Locale\Item\Site\Iface
	{
        
        
       
        
		$context = $this->getContext();

		$dbm = $context->getDatabaseManager();
        $dbname = $this->getResourceName();
        
        $conn = $dbm->acquire( $dbname );
        // try{
            
        //     $cmd = "aimeos:setup testcodetwenty";
       
        //  $output = Artisan::call($cmd);
        

        // $dbm->release( $conn);
        // }
        // catch( Exception $e )
        // {
	    // $dbm->release( $conn );
	    // throw $e;
        // }
        
        
        // exit();

		try
		{
			$date = date( 'Y-m-d H:i:s' );
			$columns = $this->getObject()->getSaveAttributes();

			/** mshop/locale/manager/site/standard/insert/mysql
			 * Inserts a new currency record into the database table
			 *
			 * @see mshop/locale/manager/site/standard/insert/ansi
			 */

			/** mshop/locale/manager/site/standard/insert/ansi
			 * Inserts a new currency record into the database table
			 *
			 * 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 site 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 saveItems() 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/update/ansi
			 * @see mshop/locale/manager/site/standard/delete/ansi
			 * @see mshop/locale/manager/site/standard/search/ansi
			 * @see mshop/locale/manager/site/standard/count/ansi
			 * @see mshop/locale/manager/site/standard/newid/ansi
			 */
			$path = 'mshop/locale/manager/site/standard/insert';
			$sql = $this->addSqlColumns( array_keys( $columns ), $this->getSqlConfig( $path ) );

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

			foreach( $columns as $name => $entry ) {
				$stmt->bind( $idx++, $item->get( $name ), $entry->getInternalType() );
			}

            $stmt->bind( $idx++, $item->getCity() );
			$stmt->bind( $idx++, '' ); // site ID
			$stmt->bind( $idx++, $item->getCode() );
			$stmt->bind( $idx++, $item->getLabel() );
			$stmt->bind( $idx++, json_encode( $item->getConfig() ) );
			$stmt->bind( $idx++, $item->getStatus(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
			$stmt->bind( $idx++, $context->getEditor() );
			$stmt->bind( $idx++, $date ); // mtime
			$stmt->bind( $idx++, $date ); // ctime

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

			/** 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_matt_id')
			 * For SQL Server:
			 *  SELECT SCOPE_IDENTITY()
			 * For Oracle:
			 *  SELECT "seq_matt_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/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/count/ansi
			 */
			$path = 'mshop/locale/manager/standard/newid';
			$item->setId( $this->newId( $conn, $this->getSqlConfig( $path ) ) );

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

			// Add unique site identifier
            $item = $this->getObject()->saveItem( $item->setSiteId( $item->getId() . '.' ) );
            
            
		}
		catch( \Exception $e )
		{
			$dbm->release( $conn, $dbname );
			throw $e;
		}

		return $item;
	}

	
 
    public function getSearchAttributes( bool $withsub = true ) : array
    {   
        $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 $data = [] ) : \Aimeos\MShop\Locale\Item\Site\Iface
	{   
        return new \Aimeos\MShop\Locale\Item\Site\Myproject( $data );
    }
    
    
   
}


khizar
Posts: 99
Joined: 19 Jan 2021, 09:51

Re: site form - update attributes table

Post by khizar » 02 Feb 2021, 06:05

please guide me is there any way to achieve this task

khizar
Posts: 99
Joined: 19 Jan 2021, 09:51

Re: site form - update attributes table

Post by khizar » 03 Feb 2021, 05:30

waiting for reply

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

Re: site form - update attributes table

Post by aimeos » 03 Feb 2021, 08:21

Creating a new site doesn't add the required data automatically like you've noticed but for new top level sites, it's required. The latest Aimeos distribution already contains the code for adding the data for new sites and you should use that version or at least its code as reference:
https://github.com/aimeos/aimeos/blob/m ... p#L75-L118

In your current code it seems like your code executes

Code: Select all

$dbm->acquire()
but doesn't always do a

Code: Select all

$dbm->release()
afterwards. Thus, you leak database connections until the database refuses to accept new ones.
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos, Image give us a star

khizar
Posts: 99
Joined: 19 Jan 2021, 09:51

Re: site form - update attributes table

Post by khizar » 03 Feb 2021, 08:42

aimeos wrote: 03 Feb 2021, 08:21 Creating a new site doesn't add the required data automatically like you've noticed but for new top level sites, it's required. The latest Aimeos distribution already contains the code for adding the data for new sites and you should use that version or at least its code as reference:
https://github.com/aimeos/aimeos/blob/m ... p#L75-L118

In your current code it seems like your code executes

Code: Select all

$dbm->acquire()
but doesn't always do a

Code: Select all

$dbm->release()
afterwards. Thus, you leak database connections until the database refuses to accept new ones.

Code: Select all

	<?php
namespace Aimeos\MShop\Locale\Manager\Site;

use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Storage;

class Myproject extends Standard
{
    private $searchConfig = array(
        'locale.site.city'=> array(
            'code'=>'locale.site.city',
            'internalcode'=>'mlocsi."city"',
            'label'=>'Product oldcode',
            'type'=> 'string', // integer, float, etc.
            'internaltype'=> \Aimeos\MW\DB\Statement\Base::PARAM_STR, // _INT, _FLOAT, etc.
        ),
    );


 
    public function saveItem( \Aimeos\MShop\Locale\Item\Site\Iface $item, bool $fetch = true ) : \Aimeos\MShop\Locale\Item\Site\Iface
	{   
		
		
		if( $item->getId() === null ) {
			throw new \Aimeos\MShop\Locale\Exception( sprintf( 'Newly created site can not be saved using method "saveItem()". Try using method "insertItem()" instead.' ) );
		}

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

		$context = $this->getContext();

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

		try
		{
			$id = $item->getId();
			$columns = $this->getObject()->getSaveAttributes();

			/** mshop/locale/manager/site/standard/update/mysql
			 * Updates an existing site record in the database
			 *
			 * @see mshop/locale/manager/site/standard/update/ansi
			 */

			/** mshop/locale/manager/site/standard/update/ansi
			 * Updates an existing site record 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 site item to the statement before they are
			 * sent to the database server. The order of the columns must
			 * correspond to the order in the saveItems() 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/insert/ansi
			 * @see mshop/locale/manager/site/standard/delete/ansi
			 * @see mshop/locale/manager/site/standard/search/ansi
			 * @see mshop/locale/manager/site/standard/count/ansi
			 * @see mshop/locale/manager/site/standard/newid/ansi
			 */
			$path = 'mshop/locale/manager/site/standard/update';
			$sql = $this->addSqlColumns( array_keys( $columns ), $this->getSqlConfig( $path ), false );

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

			foreach( $columns as $name => $entry ) {
				$stmt->bind( $idx++, $item->get( $name ), $entry->getInternalType() );
			}

            $stmt->bind( $idx++, $item->getCity() );
            $stmt->bind( $idx++, $item->getSiteId() );
			$stmt->bind( $idx++, $item->getCode() );
			$stmt->bind( $idx++, $item->getLabel() );
			$stmt->bind( $idx++, json_encode( $item->getConfig() ) );
			$stmt->bind( $idx++, $item->getStatus(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
			$stmt->bind( $idx++, $context->getEditor() );
			$stmt->bind( $idx++, date( 'Y-m-d H:i:s' ) ); // mtime
			$stmt->bind( $idx++, $id, \Aimeos\MW\DB\Statement\Base::PARAM_INT );
          
			$stmt->execute()->finish();
			$item->setId( $id ); // set Modified false


			if($item->getLogo()){
				unlink('images/'.$item->getCode().'.jpg');

				$imageName = $item->getCode().'.jpg';
				$item->getLogo()->move(public_path('/images'), $imageName);

			}

			$dbm->release( $conn, $dbname );
		}
		catch( \Exception $e )
		{
			$dbm->release( $conn, $dbname );
			throw $e;
		}

		return $item;
	}

    protected function getDbConfig( \Aimeos\MW\Config\Iface $conf ) : array
	{
		$dbconfig = $conf->get( 'resource', array() );

		foreach( $dbconfig as $rname => $dbconf )
		{
			if( strncmp( $rname, 'db', 2 ) !== 0 ) {
				unset( $dbconfig[$rname] );
			} else {
				$conf->set( 'resource/' . $rname . '/limit', 5 );
			}
		}

		return $dbconfig;
    }
    
    public function insertItem( \Aimeos\MShop\Locale\Item\Site\Iface $item, string $parentId = null, string $refId = null ) : \Aimeos\MShop\Locale\Item\Site\Iface
	{
        
        
       
        
        $context = $this->getContext();
        

		$dbm = $context->getDatabaseManager();
        $dbname = $this->getResourceName();
        
        
        $conn = $dbm->acquire( $dbname );
		
		
		// dd($item->getLogo()->store());
		// $item->getLogo()->storeAs('images/','mylogo.jpeg',['disk' => 'public']);
		

		
        

		try
		{
			$date = date( 'Y-m-d H:i:s' );
			$columns = $this->getObject()->getSaveAttributes();

			

		

			/** mshop/locale/manager/site/standard/insert/mysql
			 * Inserts a new currency record into the database table
			 *
			 * @see mshop/locale/manager/site/standard/insert/ansi
			 */

			/** mshop/locale/manager/site/standard/insert/ansi
			 * Inserts a new currency record into the database table
			 *
			 * 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 site 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 saveItems() 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/update/ansi
			 * @see mshop/locale/manager/site/standard/delete/ansi
			 * @see mshop/locale/manager/site/standard/search/ansi
			 * @see mshop/locale/manager/site/standard/count/ansi
			 * @see mshop/locale/manager/site/standard/newid/ansi
			 */
			$path = 'mshop/locale/manager/site/standard/insert';
			$sql = $this->addSqlColumns( array_keys( $columns ), $this->getSqlConfig( $path ) );

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

			foreach( $columns as $name => $entry ) {
				$stmt->bind( $idx++, $item->get( $name ), $entry->getInternalType() );
			}

            $stmt->bind( $idx++, $item->getCity() );
			$stmt->bind( $idx++, '' ); // site ID
			$stmt->bind( $idx++, $item->getCode() );
			$stmt->bind( $idx++, $item->getLabel() );
			$stmt->bind( $idx++, json_encode( $item->getConfig() ) );
			$stmt->bind( $idx++, $item->getStatus(), \Aimeos\MW\DB\Statement\Base::PARAM_INT );
			$stmt->bind( $idx++, $context->getEditor() );
			$stmt->bind( $idx++, $date ); // mtime
			$stmt->bind( $idx++, $date ); // ctime

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

			$imageName = $item->getCode().'.jpg';
			$item->getLogo()->move(public_path('/images'), $imageName);

			/** 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_matt_id')
			 * For SQL Server:
			 *  SELECT SCOPE_IDENTITY()
			 * For Oracle:
			 *  SELECT "seq_matt_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/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/count/ansi
			 */
			$path = 'mshop/locale/manager/standard/newid';
            		$item->setId( $this->newId( $conn, $this->getSqlConfig( $path ) ) );
			 
			 // this is the code which i used from thre reference you gave
			$paths = app( 'aimeos' )->get()->getSetupPaths( 'default' );
             $config = $context->getConfig()->set( 'setup/site', $item->getCode() );
             $dbconf = $this->getDbConfig( $config );
          
			 \Aimeos\MShop::cache( false );
			 \Aimeos\MAdmin::cache( false );
			
		 $setup = new \Aimeos\MW\Setup\Manager\Multiple( $dbm, $dbconf, $paths, $context );
             ob_start();
             $setup->migrate();
             ob_end_clean();
             
             // this the end of that code
            

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

			// Add unique site identifier
            // $item = $this->getObject()->saveItem( $item->setSiteId( $item->getId() . '.' ) );
            
            
		}
		catch( \Exception $e )
		{
			$dbm->release( $conn, $dbname );
			throw $e;
		}

		return $item;
	}

	
 
    public function getSearchAttributes( bool $withsub = true ) : array
    {   
        $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 $data = [] ) : \Aimeos\MShop\Locale\Item\Site\Iface
	{   
        return new \Aimeos\MShop\Locale\Item\Site\Myproject( $data );
    }
    
    
   
}
i have posted the manager class above in which i have used the code from the reference you have given,
inside insert methodat the end but when i save site the the codes start processing and processing and nothing happen can you please tell me
what i am doing wrong

khizar
Posts: 99
Joined: 19 Jan 2021, 09:51

Re: site form - update attributes table

Post by khizar » 04 Feb 2021, 07:28

waiting for reply

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

Re: site form - update attributes table

Post by aimeos » 05 Feb 2021, 08:36

The class you've posted is your own Locale Site manager class but not an extended version of the Attribute manager class
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos, Image give us a star

khizar
Posts: 99
Joined: 19 Jan 2021, 09:51

Re: site form - update attributes table

Post by khizar » 16 Feb 2021, 05:46

aimeos wrote: 05 Feb 2021, 08:36 The class you've posted is your own Locale Site manager class but not an extended version of the Attribute manager class
what do you mean extended version of the Attribute manager class.it should be the extended version of Locale Site manager class because i am storing sites from site form so it should use the manager of Locale site according to my understanding.
can you please explain little bit and guide me if i am in wrong direction

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

Re: site form - update attributes table

Post by aimeos » 17 Feb 2021, 08:48

Sorry, haven't seen that the insertItem() contains additional code.

The code seems more or less OK but you should release the connection first before you start the setup manager. If it doesn't work when inserting new sites at the root level, you have to add debug statements in your code and in the Aimeos code to find out what happens.
Professional support and custom implementation are available at Aimeos.com
If you like Aimeos, Image give us a star

Post Reply