├── .gitignore
├── themes
└── typo3
│ └── admin.css
├── manifest.jsb2
├── setup
├── CustomerClearPropertyKeyTypo3.php
├── CustomerMigratePropertyKeyTypo3.php
├── CustomerRenameGroupTypo3.php
├── unittest
│ ├── CustomerAddFeusers.php
│ ├── GroupAddTypo3TestData.php
│ ├── CustomerAddTypo3TestData.php
│ └── schema
│ │ └── customer.php
├── FEUsersMigrateCountryTypo3.php
├── CustomerRemoveIndexesTypo3.php
└── default
│ └── schema
│ └── customer.php
├── tests
├── phpunit.xml
├── bootstrap.php
├── phpunit-coverage.xml
├── Base
│ ├── View
│ │ ├── Helper
│ │ │ ├── Response
│ │ │ │ └── Typo3Test.php
│ │ │ ├── Request
│ │ │ │ └── Typo3Test.php
│ │ │ └── Url
│ │ │ │ ├── T3RouterTest.php
│ │ │ │ └── Typo3Test.php
│ │ └── Engine
│ │ │ └── Typo3Test.php
│ ├── Mail
│ │ ├── Manager
│ │ │ └── Typo3Test.php
│ │ ├── Typo3Test.php
│ │ └── Message
│ │ │ └── Typo3Test.php
│ ├── Password
│ │ └── Typo3Test.php
│ ├── Criteria
│ │ └── Plugin
│ │ │ ├── T3StatusTest.php
│ │ │ ├── T3DateTest.php
│ │ │ ├── T3DatetimeTest.php
│ │ │ └── T3SalutationTest.php
│ ├── Session
│ │ └── Typo3Test.php
│ └── Cache
│ │ └── Typo3Test.php
├── TestHelper.php
└── MShop
│ ├── Group
│ └── Manager
│ │ └── Typo3Test.php
│ └── Customer
│ └── Manager
│ ├── Lists
│ ├── Type
│ │ └── Typo3Test.php
│ └── Typo3Test.php
│ ├── Property
│ ├── Type
│ │ └── Typo3Test.php
│ └── Typo3Test.php
│ ├── Address
│ └── Typo3Test.php
│ └── Typo3Test.php
├── manifest.php
├── src
├── Base
│ ├── View
│ │ ├── Helper
│ │ │ ├── Response
│ │ │ │ └── Typo3.php
│ │ │ ├── Url
│ │ │ │ ├── T3Router.php
│ │ │ │ └── Typo3.php
│ │ │ └── Request
│ │ │ │ └── Typo3.php
│ │ └── Engine
│ │ │ └── Typo3.php
│ ├── Mail
│ │ ├── Manager
│ │ │ └── Typo3.php
│ │ ├── Typo3.php
│ │ └── Message
│ │ │ └── Typo3.php
│ ├── Criteria
│ │ └── Plugin
│ │ │ ├── T3Status.php
│ │ │ ├── T3Date.php
│ │ │ ├── T3Datetime.php
│ │ │ └── T3Salutation.php
│ ├── Password
│ │ └── Typo3.php
│ ├── Session
│ │ └── Typo3.php
│ └── Cache
│ │ └── Typo3.php
└── MShop
│ ├── Customer
│ └── Manager
│ │ ├── Lists
│ │ ├── Type
│ │ │ └── Typo3.php
│ │ └── Typo3.php
│ │ ├── Property
│ │ ├── Type
│ │ │ └── Typo3.php
│ │ └── Typo3.php
│ │ └── Address
│ │ └── Typo3.php
│ └── Group
│ └── Manager
│ └── Typo3.php
├── composer.json
├── README.md
├── phing.xml
├── config
└── mshop
│ ├── group.php
│ └── customer.php
├── LICENSE
└── .circleci
└── config.yml
/.gitignore:
--------------------------------------------------------------------------------
1 | .phpunit.result.cache
2 | .phpunit.cache
3 | coveralls.json
4 | coverage.xml
5 | *.log
6 | *.ser
7 |
--------------------------------------------------------------------------------
/themes/typo3/admin.css:
--------------------------------------------------------------------------------
1 | /*
2 | * TYPO3 JQAdm theme
3 | */
4 |
5 | html, body {
6 | font-family: Verdana, Arial, Helvetica, sans-serif;
7 | font-size: 14px;
8 | overflow: auto;
9 | height: 100%;
10 | }
11 |
--------------------------------------------------------------------------------
/manifest.jsb2:
--------------------------------------------------------------------------------
1 | {
2 | "projectName": "Aimeos TYPO3 extension",
3 | "licenseText": "LGPLv3, http://www.gnu.org/licenses/lgpl.html",
4 | "pkgs": [{
5 | "name": "Aimeos Admin TYPO3 CSS",
6 | "file": "index-css",
7 | "isDebug": true,
8 | "fileIncludes": [{
9 | "text": "admin.css",
10 | "path": "themes/typo3/"
11 | }]
12 | }],
13 | "resources" : []
14 | }
15 |
--------------------------------------------------------------------------------
/setup/CustomerClearPropertyKeyTypo3.php:
--------------------------------------------------------------------------------
1 | 'fe_users_property',
18 | ];
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/setup/CustomerMigratePropertyKeyTypo3.php:
--------------------------------------------------------------------------------
1 | 'fe_users_property',
18 | ];
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/tests/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Base/
6 |
7 |
8 | MShop/
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/manifest.php:
--------------------------------------------------------------------------------
1 | 'ai-typo3',
12 | 'depends' => [
13 | 'aimeos-core',
14 | ],
15 | 'include' => [
16 | 'src',
17 | ],
18 | 'config' => [
19 | 'config',
20 | ],
21 | 'setup' => [
22 | 'setup',
23 | ],
24 | 'custom' => [
25 | 'admin/jqadm' => [
26 | 'manifest.jsb2',
27 | ],
28 | ],
29 | ];
30 |
--------------------------------------------------------------------------------
/setup/CustomerRenameGroupTypo3.php:
--------------------------------------------------------------------------------
1 | info( 'Migrate TYPO3 "customer/group" domain to "group"', 'vv' );
23 |
24 | $this->update( 'fe_users_list' );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ../src
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Base/
16 |
17 |
18 | MShop/
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/tests/Base/View/Helper/Response/Typo3Test.php:
--------------------------------------------------------------------------------
1 | object = new \Aimeos\Base\View\Helper\Response\Typo3( $view );
21 | }
22 |
23 |
24 | protected function tearDown() : void
25 | {
26 | unset( $this->object );
27 | }
28 |
29 |
30 | public function testTransform()
31 | {
32 | $this->assertInstanceOf( '\Aimeos\Base\View\Helper\Response\Typo3', $this->object->transform() );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/setup/unittest/CustomerAddFeusers.php:
--------------------------------------------------------------------------------
1 | info( 'Creating fe_users schema', 'vv' );
23 | $db = $this->db( 'db-customer' );
24 |
25 | $filepath = __DIR__ . '/schema/customer.php';
26 |
27 | if( ( $list = include( $filepath ) ) === false ) {
28 | throw new \RuntimeException( sprintf( 'Unable to get schema from file "%1$s"', $filepath ) );
29 | }
30 |
31 | foreach( $list['table'] ?? [] as $name => $fcn ) {
32 | $db->table( $name, $fcn );
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/tests/Base/Mail/Manager/Typo3Test.php:
--------------------------------------------------------------------------------
1 | markTestSkipped( 'Class TYPO3\\CMS\\Core\\Mail\\MailMessage not found' );
21 | }
22 |
23 | $this->mock = $this->getMockBuilder( 'TYPO3\\CMS\\Core\\Mail\\MailMessage' )
24 | ->disableOriginalConstructor()
25 | ->getMock();
26 | }
27 |
28 |
29 | public function testGet()
30 | {
31 | $object = new \Aimeos\Base\Mail\Manager\Typo3( fn() => $this->mock );
32 | $this->assertInstanceOf( \Aimeos\Base\Mail\Iface::class, $object->get( '' ) );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Base/View/Helper/Response/Typo3.php:
--------------------------------------------------------------------------------
1 | createResponse() );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Base/Mail/Manager/Typo3.php:
--------------------------------------------------------------------------------
1 | closure = $closure;
32 | }
33 |
34 |
35 | /**
36 | * Returns the mailer for the given name
37 | *
38 | * @param string|null $name Key for the mailer
39 | * @return \Aimeos\Base\Mail\Iface Mail object
40 | */
41 | public function get( ?string $name = null ) : \Aimeos\Base\Mail\Iface
42 | {
43 | return new \Aimeos\Base\Mail\Typo3( $this->closure );
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/tests/Base/Password/Typo3Test.php:
--------------------------------------------------------------------------------
1 | markTestSkipped( 'TYPO3 password hashing not available' );
21 | }
22 |
23 | $this->object = new \Aimeos\Base\Password\Typo3( new \TYPO3\CMS\Core\Crypto\PasswordHashing\Md5PasswordHash() );
24 | }
25 |
26 |
27 | protected function tearDown() : void
28 | {
29 | unset( $this->object );
30 | }
31 |
32 |
33 | public function testHash()
34 | {
35 | $this->assertStringStartsWith( '$1$', $this->object->hash( 'unittest' ) );
36 | }
37 |
38 |
39 | public function testVerify()
40 | {
41 | $this->assertTrue( $this->object->verify( 'unittest', $this->object->hash( 'unittest' ) ) );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/MShop/Customer/Manager/Lists/Type/Typo3.php:
--------------------------------------------------------------------------------
1 | '127.0.0.1' );
21 | $this->object = new \Aimeos\Base\View\Helper\Request\Typo3( $view, 123, [], [], [], [], $server );
22 | }
23 |
24 |
25 | protected function tearDown() : void
26 | {
27 | unset( $this->object );
28 | }
29 |
30 |
31 | public function testTransform()
32 | {
33 | $this->assertInstanceOf( '\Aimeos\Base\View\Helper\Request\Typo3', $this->object->transform() );
34 | }
35 |
36 |
37 | public function testGetClientAddress()
38 | {
39 | $this->assertEquals( '127.0.0.1', $this->object->getClientAddress() );
40 | }
41 |
42 |
43 | public function testGetTarget()
44 | {
45 | $this->assertEquals( 123, $this->object->getTarget() );
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/setup/FEUsersMigrateCountryTypo3.php:
--------------------------------------------------------------------------------
1 | db( 'db-customer' );
34 |
35 | if( !$db->hasTable( ['fe_users', 'static_countries'] ) || !$db->hasColumn( 'fe_users', 'static_info_country' ) ) {
36 | return;
37 | }
38 |
39 | $this->info( 'Migrating "static_info_country" column in "fe_users" table', 'vv' );
40 |
41 | $db->exec( '
42 | UPDATE fe_users SET static_info_country = (
43 | SELECT cn_iso_2 FROM static_countries WHERE cn_iso_3 = static_info_country
44 | ) WHERE LENGTH(static_info_country) = 3
45 | ' );
46 | }
47 | }
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aimeos/ai-typo3",
3 | "description": "TYPO3 adapter for Aimeos e-commerce integration",
4 | "keywords": ["aimeos", "adapter", "typo3", "cms", "shop", "e-commerce"],
5 | "homepage": "https://aimeos.org/TYPO3",
6 | "type": "aimeos-extension",
7 | "license": "LGPL-3.0-or-later",
8 | "support": {
9 | "source": "https://github.com/Aimeos/ai-typo3",
10 | "issues": "https://github.com/Aimeos/ai-typo3/issues",
11 | "forum": "https://aimeos.org/help",
12 | "wiki": "https://aimeos.org/docs"
13 | },
14 | "prefer-stable": true,
15 | "minimum-stability": "dev",
16 | "require": {
17 | "php": "^8.0.11",
18 | "ext-fileinfo": "*",
19 | "nyholm/psr7": "~1.2",
20 | "nyholm/psr7-server": "~1.0",
21 | "aimeos/aimeos-core": "dev-master"
22 | },
23 | "require-dev": {
24 | "typo3/cms-core": "~12.3||~13.4",
25 | "typo3/cms-extbase": "~12.3||~13.4",
26 | "phpunit/phpunit": "~10.0||~11.0"
27 | },
28 | "autoload": {
29 | "psr-4": {
30 | "Aimeos\\": "src"
31 | },
32 | "classmap": [
33 | "src"
34 | ]
35 | },
36 | "autoload-dev": {
37 | "psr-4": {
38 | "Aimeos\\": "tests"
39 | },
40 | "classmap": [
41 | "tests"
42 | ]
43 | },
44 | "config": {
45 | "allow-plugins": true
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Base/Criteria/Plugin/T3Status.php:
--------------------------------------------------------------------------------
1 | markTestSkipped( 'Class TYPO3\\CMS\\Core\\Mail\\MailMessage not found' );
23 | }
24 |
25 | $mock = $this->getMockBuilder( 'TYPO3\\CMS\\Core\\Mail\\MailMessage' )
26 | ->disableOriginalConstructor()
27 | ->getMock();
28 |
29 | $this->object = new \Aimeos\Base\Mail\Typo3( function() use ( $mock ) { return $mock; } );
30 | $this->mock = $mock;
31 | }
32 |
33 |
34 | public function testCreate()
35 | {
36 | $result = $this->object->create( 'ISO-8859-1' );
37 | $this->assertInstanceOf( '\\Aimeos\\Base\\Mail\\Message\\Iface', $result );
38 | }
39 |
40 |
41 | public function testSend()
42 | {
43 | $this->mock->expects( $this->once() )->method( 'send' );
44 |
45 | $this->object->send( $this->object->create() );
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/tests/Base/View/Engine/Typo3Test.php:
--------------------------------------------------------------------------------
1 | markTestSkipped( '\TYPO3\CMS\Fluid\View\StandaloneView not available' );
17 | }
18 |
19 | $view = $this->getMockBuilder( '\TYPO3\CMS\Fluid\View\StandaloneView' )
20 | ->onlyMethods( ['assign', 'assignMultiple', 'render', 'setTemplatePathAndFilename', 'setPartialRootPaths', 'setLayoutRootPaths'] )
21 | ->disableOriginalConstructor()
22 | ->getMock();
23 |
24 | $view->expects( $this->once() )->method( 'setTemplatePathAndFilename' );
25 | $view->expects( $this->once() )->method( 'assignMultiple' );
26 | $view->expects( $this->once() )->method( 'assign' );
27 | $view->expects( $this->once() )->method( 'render' )->willReturn( 'test' );
28 |
29 | $object = new \Aimeos\Base\View\Engine\Typo3( $view );
30 | $v = new \Aimeos\Base\View\Standard( [] );
31 |
32 | $this->assertEquals( 'test', $object->render( $v, 'filepath', ['key' => 'value'] ) );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/tests/Base/View/Helper/Url/T3RouterTest.php:
--------------------------------------------------------------------------------
1 | markTestSkipped( 'TYPO3 Router not available' );
22 | }
23 |
24 | $this->view = new \Aimeos\Base\View\Standard();
25 | }
26 |
27 |
28 | protected function tearDown() : void
29 | {
30 | unset( $this->view );
31 | }
32 |
33 |
34 | public function testTransform()
35 | {
36 | $mock = $this->getMockBuilder( 'TYPO3\CMS\Core\Routing\RouterInterface' )
37 | ->onlyMethods( array( 'generateUri', 'matchRequest' ) )->getMock();
38 |
39 | $stub = $this->getMockBuilder( 'Psr\Http\Message\UriInterface' )->getMock();
40 |
41 | $mock->expects( $this->once() )->method( 'generateUri' )->willReturn( $stub );
42 |
43 | $object = new \Aimeos\Base\View\Helper\Url\T3Router( $this->view, $mock, [] );
44 |
45 | $this->assertEquals( '', $object->transform() );
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/MShop/Customer/Manager/Property/Typo3.php:
--------------------------------------------------------------------------------
1 | object = new \Aimeos\Base\Criteria\Plugin\T3Status();
27 | }
28 |
29 |
30 | /**
31 | * Tears down the fixture. This method is called after a test is executed.
32 | */
33 | protected function tearDown() : void
34 | {
35 | unset( $this->object );
36 | }
37 |
38 |
39 | public function testTranslate()
40 | {
41 | $this->assertEquals( 0, $this->object->translate( 1 ) );
42 | }
43 |
44 |
45 | public function testTranslateDisabled()
46 | {
47 | $this->assertEquals( 1, $this->object->translate( 0 ) );
48 | }
49 |
50 |
51 | public function testReverse()
52 | {
53 | $this->assertEquals( 1, $this->object->reverse( 0 ) );
54 | }
55 |
56 |
57 | public function testReverseDisabled()
58 | {
59 | $this->assertEquals( 0, $this->object->reverse( 1 ) );
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/setup/unittest/GroupAddTypo3TestData.php:
--------------------------------------------------------------------------------
1 | info( 'Adding TYPO3 group test data', 'vv' );
34 |
35 | $this->db( 'db-group' )->exec( "DELETE FROM fe_groups WHERE title LIKE 'unitgroup%'" );
36 |
37 | $this->context()->setEditor( 'ai-typo3' );
38 | $this->process();
39 | }
40 |
41 |
42 | /**
43 | * Returns the manager for the current setup task
44 | *
45 | * @param string $domain Domain name of the manager
46 | * @param string $name Specific manager implemenation
47 | * @return \Aimeos\MShop\Common\Manager\Iface Manager object
48 | */
49 | protected function getManager( string $domain, string $name = 'Standard' ) : \Aimeos\MShop\Common\Manager\Iface
50 | {
51 | if( $domain === 'group' ) {
52 | return parent::getManager( $domain, 'Typo3' );
53 | }
54 |
55 | return parent::getManager( $domain );
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/MShop/Customer/Manager/Address/Typo3.php:
--------------------------------------------------------------------------------
1 | createAttributes( [
32 | 'customer.address.id' => [
33 | 'label' => 'Customer address ID',
34 | 'internalcode' => 'id',
35 | 'internaldeps' => ['LEFT JOIN "fe_users_address" AS mcusad ON ( mcus."uid" = mcusad."parentid" )'],
36 | 'type' => 'int',
37 | 'public' => false,
38 | ]
39 | ] ) );
40 | }
41 |
42 |
43 | /**
44 | * Returns the name of the used table
45 | *
46 | * @return string Table name
47 | */
48 | protected function table() : string
49 | {
50 | return 'fe_users_address';
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/setup/unittest/CustomerAddTypo3TestData.php:
--------------------------------------------------------------------------------
1 | info( 'Adding TYPO3 customer test data', 'vv' );
34 |
35 | $this->db( 'db-customer' )->exec( "DELETE FROM fe_users WHERE email LIKE 'test%@example.com'" );
36 |
37 | $this->context()->setEditor( 'ai-typo3' );
38 | $this->process();
39 | }
40 |
41 |
42 | /**
43 | * Returns the manager for the current setup task
44 | *
45 | * @param string $domain Domain name of the manager
46 | * @param string $name Specific manager implemenation
47 | * @return \Aimeos\MShop\Common\Manager\Iface Manager object
48 | */
49 | protected function getManager( string $domain, string $name = 'Standard' ) : \Aimeos\MShop\Common\Manager\Iface
50 | {
51 | if( $domain === 'customer' ) {
52 | return parent::getManager( $domain, 'Typo3' );
53 | }
54 |
55 | return parent::getManager( $domain );
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Base/Mail/Typo3.php:
--------------------------------------------------------------------------------
1 | closure = $closure;
33 | }
34 |
35 |
36 | /**
37 | * Creates a new e-mail message object.
38 | *
39 | * @param string $charset Default charset of the message
40 | * @return \Aimeos\Base\Mail\Message\Iface E-mail message object
41 | */
42 | public function create( string $charset = 'UTF-8' ) : \Aimeos\Base\Mail\Message\Iface
43 | {
44 | $closure = $this->closure;
45 | return new \Aimeos\Base\Mail\Message\Typo3( $closure(), $charset );
46 | }
47 |
48 |
49 | /**
50 | * Sends the e-mail message to the mail server.
51 | *
52 | * @param \Aimeos\Base\Mail\Message\Iface $message E-mail message object
53 | */
54 | public function send( \Aimeos\Base\Mail\Message\Iface $message ) : Iface
55 | {
56 | $message->object()->send();
57 | return $this;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Base/View/Engine/Typo3.php:
--------------------------------------------------------------------------------
1 | view = $view;
34 | }
35 |
36 |
37 | /**
38 | * Renders the output based on the given template file name and the key/value pairs
39 | *
40 | * @param \Aimeos\Base\View\Iface $view View object
41 | * @param string $filename File name of the view template
42 | * @param array $values Associative list of key/value pairs
43 | * @return string Output generated by the template
44 | * @throws \Aimeos\Base\View\Exception If the template isn't found
45 | */
46 | public function render( \Aimeos\Base\View\Iface $view, string $filename, array $values ) : string
47 | {
48 | $fluid = clone $this->view;
49 | $fluid->setTemplatePathAndFilename( $filename );
50 | $fluid->assign( '_aimeos_view', $view );
51 | $fluid->assignMultiple( $values );
52 |
53 | return $fluid->render();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/Base/Password/Typo3.php:
--------------------------------------------------------------------------------
1 | hasher = $hasher;
33 | }
34 |
35 |
36 | /**
37 | * Returns the hashed password
38 | *
39 | * @param string $password Clear text password string
40 | * @return string Hashed password
41 | */
42 | public function hash( string $password ) : string
43 | {
44 | return $this->hasher->getHashedPassword( $password );
45 | }
46 |
47 |
48 | /**
49 | * Verifies the password
50 | *
51 | * @param string $password Clear text password string
52 | * @param string $hash Hashed password
53 | * @return bool TRUE if password and hash match
54 | */
55 | public function verify( string $password, string $hash ) : bool
56 | {
57 | return $this->hasher->checkPassword( $password, $hash );
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/Base/Criteria/Plugin/T3Salutation.php:
--------------------------------------------------------------------------------
1 | object = new \Aimeos\Base\Criteria\Plugin\T3Date();
27 | }
28 |
29 |
30 | /**
31 | * Tears down the fixture. This method is called after a test is executed.
32 | */
33 | protected function tearDown() : void
34 | {
35 | unset( $this->object );
36 | }
37 |
38 |
39 | public function testTranslate()
40 | {
41 | $this->assertEquals( 86400, $this->object->translate( '1970-01-02' ) );
42 | }
43 |
44 |
45 | public function testTranslateNull()
46 | {
47 | $this->assertEquals( 0, $this->object->translate( null ) );
48 | }
49 |
50 |
51 | public function testTranslateNegative()
52 | {
53 | $this->assertEquals( -86400, $this->object->translate( '1969-12-31' ) );
54 | }
55 |
56 |
57 | public function testReverse()
58 | {
59 | $this->assertEquals( '1970-01-02', $this->object->reverse( 86400 ) );
60 | }
61 |
62 |
63 | public function testReverseZero()
64 | {
65 | $this->assertEquals( null, $this->object->reverse( 0 ) );
66 | }
67 |
68 |
69 | public function testReverseNegative()
70 | {
71 | $this->assertEquals( '1969-12-31', $this->object->reverse( -86400 ) );
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/tests/Base/Criteria/Plugin/T3DatetimeTest.php:
--------------------------------------------------------------------------------
1 | object = new \Aimeos\Base\Criteria\Plugin\T3Datetime();
26 | }
27 |
28 |
29 | /**
30 | * Tears down the fixture. This method is called after a test is executed.
31 | */
32 | protected function tearDown() : void
33 | {
34 | unset( $this->object );
35 | }
36 |
37 |
38 | public function testTranslate()
39 | {
40 | $this->assertEquals( 3661, $this->object->translate( '1970-01-01 01:01:01' ) );
41 | }
42 |
43 |
44 | public function testTranslateNull()
45 | {
46 | $this->assertEquals( 0, $this->object->translate( null ) );
47 | }
48 |
49 |
50 | public function testTranslateNegative()
51 | {
52 | $this->assertEquals( -1, $this->object->translate( '1969-12-31 23:59:59' ) );
53 | }
54 |
55 |
56 | public function testReverse()
57 | {
58 | $this->assertEquals( '1970-01-01 01:01:01', $this->object->reverse( 3661 ) );
59 | }
60 |
61 |
62 | public function testReverseZero()
63 | {
64 | $this->assertEquals( null, $this->object->reverse( 0 ) );
65 | }
66 |
67 |
68 | public function testReverseNegative()
69 | {
70 | $this->assertEquals( '1969-12-31 23:59:59', $this->object->reverse( -1 ) );
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/setup/CustomerRemoveIndexesTypo3.php:
--------------------------------------------------------------------------------
1 | info( 'Remove customer indexes with siteid column first', 'vv' );
23 |
24 | $this->db( 'db-customer' )
25 | ->dropIndex( 'fe_users_address', 'idx_t3feuad_langid' )
26 | ->dropIndex( 'fe_users_address', 'idx_t3feuad_sid_last_first' )
27 | ->dropIndex( 'fe_users_address', 'idx_t3feuad_sid_post_addr1' )
28 | ->dropIndex( 'fe_users_address', 'idx_t3feuad_sid_post_ci' )
29 | ->dropIndex( 'fe_users_address', 'idx_t3feuad_sid_city' )
30 | ->dropIndex( 'fe_users_address', 'idx_t3feuad_sid_email' )
31 | ->dropIndex( 'fe_users_list', 'unq_t3feuli_pid_dm_sid_ty_rid' )
32 | ->dropIndex( 'fe_users_list_type', 'unq_t3feulity_sid_dom_code' )
33 | ->dropIndex( 'fe_users_list_type', 'idx_t3feulity_sid_status_pos' )
34 | ->dropIndex( 'fe_users_list_type', 'idx_t3feulity_sid_label' )
35 | ->dropIndex( 'fe_users_list_type', 'idx_t3feulity_sid_code' )
36 | ->dropIndex( 'fe_users_property', 'fk_t3feupr_key_sid' )
37 | ->dropIndex( 'fe_users_property', 'unq_t3feupr_sid_ty_lid_value' )
38 | ->dropIndex( 'fe_users_property_type', 'unq_t3feuprty_sid_dom_code' )
39 | ->dropIndex( 'fe_users_property_type', 'idx_t3feuprty_sid_status_pos' )
40 | ->dropIndex( 'fe_users_property_type', 'idx_t3feuprty_sid_label' )
41 | ->dropIndex( 'fe_users_property_type', 'idx_t3feuprty_sid_code' )
42 | ->dropIndex( 'fe_users_property_type', 'fk_t3feupr_key_sid' );
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # Aimeos TYPO3 adapter
6 |
7 | [](https://circleci.com/gh/aimeos/ai-typo3)
8 | [](https://coveralls.io/github/aimeos/ai-typo3?branch=master)
9 | [](https://scrutinizer-ci.com/g/aimeos/ai-typo3/?branch=master)
10 | [](https://packagist.org/packages/aimeos/ai-typo3)
11 |
12 | The Aimeos web shop components can integrate into almost any PHP application and uses the infrastructure of the application for building URLs, caching content, configuration settings, logging messages, session handling, sending e-mails or handling translations.
13 |
14 | The ai-typo3 extension integrates Aimeos into the TYPO3 CMS and utilizes the native TYPO3 components for content caching, sending mails, session handling and generating URLs.
15 |
16 | If you are using the TYPO3 CMS, you don't have to install and set up the ai-typo3 extension yourself. Instead, use the [Aimeos TYPO3 package](https://github.com/aimeos/aimeos-typo3) to create a web shop within minutes.
17 |
18 | ## License
19 |
20 | The Aimeos ai-flow extension is licensed under the terms of the LGPLv3 license and is available for free.
21 |
22 | ## Links
23 |
24 | * [Web site](https://aimeos.org/TYPO3)
25 | * [Documentation](https://aimeos.org/docs/TYPO3)
26 | * [Help](https://aimeos.org/help/typo3-extension-f16/)
27 | * [Issue tracker](https://github.com/aimeos/ai-typo3/issues)
28 | * [Source code](https://github.com/aimeos/ai-typo3)
29 |
--------------------------------------------------------------------------------
/phing.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/tests/Base/Criteria/Plugin/T3SalutationTest.php:
--------------------------------------------------------------------------------
1 | object = new \Aimeos\Base\Criteria\Plugin\T3Salutation();
27 | }
28 |
29 |
30 | /**
31 | * Tears down the fixture. This method is called after a test is executed.
32 | */
33 | protected function tearDown() : void
34 | {
35 | unset( $this->object );
36 | }
37 |
38 |
39 | public function testTranslate()
40 | {
41 | $this->assertEquals( 99, $this->object->translate( '' ) );
42 | }
43 |
44 |
45 | public function testTranslateMale()
46 | {
47 | $this->assertEquals( 0, $this->object->translate( 'mr' ) );
48 | }
49 |
50 |
51 | public function testTranslateFemale()
52 | {
53 | $this->assertEquals( 1, $this->object->translate( 'ms' ) );
54 | }
55 |
56 |
57 | public function testTranslateCompany()
58 | {
59 | $this->assertEquals( 10, $this->object->translate( 'company' ) );
60 | }
61 |
62 |
63 | public function testReverse()
64 | {
65 | $this->assertEquals( '', $this->object->reverse( 99 ) );
66 | }
67 |
68 |
69 | public function testReverseMale()
70 | {
71 | $this->assertEquals( 'mr', $this->object->reverse( 0 ) );
72 | }
73 |
74 |
75 | public function testReverseFemale()
76 | {
77 | $this->assertEquals( 'ms', $this->object->reverse( 1 ) );
78 | }
79 |
80 |
81 | public function testReverseCompany()
82 | {
83 | $this->assertEquals( 'company', $this->object->reverse( 10 ) );
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/config/mshop/group.php:
--------------------------------------------------------------------------------
1 | array(
11 | 'typo3' => array(
12 | 'delete' => array(
13 | 'ansi' => '
14 | DELETE FROM "fe_groups"
15 | WHERE :cond
16 | '
17 | ),
18 | 'insert' => array(
19 | 'ansi' => '
20 | INSERT INTO "fe_groups" ( :names
21 | "pid", "title", "description", "tstamp", "crdate"
22 | ) VALUES ( :values
23 | ?, ?, ?, ?, ?
24 | )
25 | '
26 | ),
27 | 'update' => array(
28 | 'ansi' => '
29 | UPDATE "fe_groups"
30 | SET :names
31 | "pid" = ?, "title" = ?, "description" = ?, "tstamp" = ?
32 | WHERE "uid" = ?
33 | '
34 | ),
35 | 'search' => array(
36 | 'ansi' => '
37 | SELECT :columns
38 | FROM "fe_groups" mgro
39 | :joins
40 | WHERE mgro."deleted" = 0 AND :cond
41 | ORDER BY :order
42 | OFFSET :start ROWS FETCH NEXT :size ROWS ONLY
43 | ',
44 | 'mysql' => '
45 | SELECT :columns
46 | FROM "fe_groups" mgro
47 | :joins
48 | WHERE mgro."deleted" = 0 AND :cond
49 | ORDER BY :order
50 | LIMIT :size OFFSET :start
51 | ',
52 | ),
53 | 'count' => array(
54 | 'ansi' => '
55 | SELECT COUNT(*) AS "count"
56 | FROM (
57 | SELECT mgro."uid"
58 | FROM "fe_groups" mgro
59 | :joins
60 | WHERE mgro."deleted" = 0 AND :cond
61 | OFFSET 0 ROWS FETCH NEXT 10000 ROWS ONLY
62 | ) AS list
63 | ',
64 | 'mysql' => '
65 | SELECT COUNT(*) AS "count"
66 | FROM (
67 | SELECT mgro."uid"
68 | FROM "fe_groups" mgro
69 | :joins
70 | WHERE mgro."deleted" = 0 AND :cond
71 | LIMIT 10000 OFFSET 0
72 | ) AS list
73 | ',
74 | ),
75 | 'newid' => array(
76 | 'db2' => 'SELECT IDENTITY_VAL_LOCAL()',
77 | 'mysql' => 'SELECT LAST_INSERT_ID()',
78 | 'oracle' => 'SELECT fe_groups_seq.CURRVAL FROM DUAL',
79 | 'pgsql' => 'SELECT lastval()',
80 | 'sqlite' => 'SELECT last_insert_rowid()',
81 | 'sqlsrv' => 'SELECT SCOPE_IDENTITY()',
82 | 'sqlanywhere' => 'SELECT @@IDENTITY',
83 | ),
84 | ),
85 | ),
86 | );
87 |
--------------------------------------------------------------------------------
/tests/TestHelper.php:
--------------------------------------------------------------------------------
1 | getIncludePaths();
19 | $includepaths[] = get_include_path();
20 | set_include_path( implode( PATH_SEPARATOR, $includepaths ) );
21 | }
22 |
23 |
24 | public static function context( $site = 'unittest' )
25 | {
26 | if( !isset( self::$context[$site] ) ) {
27 | self::$context[$site] = self::createContext( $site );
28 | }
29 |
30 | return clone self::$context[$site];
31 | }
32 |
33 |
34 | public static function getAimeos()
35 | {
36 | if( !isset( self::$aimeos ) )
37 | {
38 | require_once 'Bootstrap.php';
39 | spl_autoload_register( 'Aimeos\\Bootstrap::autoload' );
40 |
41 | self::$aimeos = new \Aimeos\Bootstrap();
42 | }
43 |
44 | return self::$aimeos;
45 | }
46 |
47 |
48 | /**
49 | * @param string $site
50 | */
51 | private static function createContext( $site )
52 | {
53 | $ctx = new \Aimeos\MShop\Context();
54 | $mshop = self::getAimeos();
55 |
56 |
57 | $paths = $mshop->getConfigPaths();
58 | $paths[] = __DIR__ . DIRECTORY_SEPARATOR . 'config';
59 | $file = __DIR__ . DIRECTORY_SEPARATOR . 'confdoc.ser';
60 |
61 | $conf = new \Aimeos\Base\Config\PHPArray( [], $paths );
62 | $conf = new \Aimeos\Base\Config\Decorator\Memory( $conf );
63 | $conf = new \Aimeos\Base\Config\Decorator\Documentor( $conf, $file );
64 | $ctx->setConfig( $conf );
65 |
66 | $dbm = new \Aimeos\Base\DB\Manager\Standard( $conf->get( 'resource', [] ), 'PDO' );
67 | $ctx->setDatabaseManager( $dbm );
68 |
69 | $logger = new \Aimeos\Base\Logger\File( $site . '.log', \Aimeos\Base\Logger\Iface::DEBUG );
70 | $ctx->setLogger( $logger );
71 |
72 | $password = new \Aimeos\Base\Password\Standard();
73 | $ctx->setPassword( $password );
74 |
75 | $session = new \Aimeos\Base\Session\None();
76 | $ctx->setSession( $session );
77 |
78 | $localeManager = \Aimeos\MShop::create( $ctx, 'locale' );
79 | $localeItem = $localeManager->bootstrap( $site, '', '', false );
80 | $ctx->setLocale( $localeItem );
81 |
82 | return $ctx->setEditor( 'ai-typo3' );
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/tests/Base/Session/Typo3Test.php:
--------------------------------------------------------------------------------
1 | markTestSkipped( 'TYPO3 BackendUserAuthentication not available' );
23 | }
24 |
25 | $this->mock = $this->getMockBuilder( '\TYPO3\CMS\Core\Authentication\BackendUserAuthentication' )
26 | ->onlyMethods( ['getSessionData', 'setAndSaveSessionData'] )
27 | ->disableOriginalConstructor()
28 | ->getMock();
29 |
30 | $this->object = new \Aimeos\Base\Session\Typo3( $this->mock );
31 | }
32 |
33 |
34 | protected function tearDown() : void
35 | {
36 | unset( $this->object, $this->mock );
37 | }
38 |
39 |
40 | public function testDel()
41 | {
42 | $this->mock->expects( $this->once() )->method( 'setAndSaveSessionData' );
43 |
44 | $result = $this->object->del( 'test' );
45 |
46 | $this->assertInstanceOf( \Aimeos\Base\Session\Iface::class, $result );
47 | }
48 |
49 |
50 | public function testGet()
51 | {
52 | $this->mock->expects( $this->once() )->method( 'getSessionData' )->willReturn( '123456789' );
53 |
54 | $this->assertEquals( '123456789', $this->object->get( 'test' ) );
55 | }
56 |
57 |
58 | public function testPull()
59 | {
60 | $this->mock->expects( $this->once() )->method( 'setAndSaveSessionData' );
61 | $this->mock->expects( $this->once() )->method( 'getSessionData' )->willReturn( '123456789' );
62 |
63 | $this->assertEquals( '123456789', $this->object->pull( 'test' ) );
64 | }
65 |
66 |
67 | public function testRemove()
68 | {
69 | $this->mock->expects( $this->once() )->method( 'setAndSaveSessionData' );
70 |
71 | $result = $this->object->remove( ['test'] );
72 |
73 | $this->assertInstanceOf( \Aimeos\Base\Session\Iface::class, $result );
74 | }
75 |
76 |
77 | public function testSet()
78 | {
79 | $this->mock->expects( $this->once() )->method( 'setAndSaveSessionData' );
80 |
81 | $result = $this->object->set( 'test', '234' );
82 |
83 | $this->assertInstanceOf( \Aimeos\Base\Session\Iface::class, $result );
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/Base/View/Helper/Url/T3Router.php:
--------------------------------------------------------------------------------
1 | router = clone $router;
45 | $this->pageid = $pageid;
46 | $this->fixed = $fixed;
47 | }
48 |
49 |
50 | /**
51 | * Returns the URL assembled from the given arguments.
52 | *
53 | * @param string|null $target Route or page which should be the target of the link (if any)
54 | * @param string|null $controller Name of the controller which should be part of the link (if any)
55 | * @param string|null $action Name of the action which should be part of the link (if any)
56 | * @param array $params Associative list of parameters that should be part of the URL
57 | * @param array $trailing Trailing URL parts that are not relevant to identify the resource (for pretty URLs)
58 | * @param array $config Additional configuration parameter per URL
59 | * @return string Complete URL that can be used in the template
60 | */
61 | public function transform( ?string $target = null, ?string $controller = null, ?string $action = null,
62 | array $params = [], array $trailing = [], array $config = [] ) : string
63 | {
64 | $params['controller'] = $controller !== null ? ucfirst( $controller ) : null;
65 | $params['action'] = $action;
66 |
67 | if( $params['locale'] ?? null ) {
68 | $params['L'] = $params['locale'];
69 | }
70 |
71 | $abs = !empty( $config['absoluteUri'] ) ? RouterInterface::ABSOLUTE_URL : RouterInterface::ABSOLUTE_PATH;
72 |
73 | return (string) $this->router->generateUri( $target ?: $this->pageid, ['ai' => $params] + $this->fixed, join( '/', $trailing ), $abs );
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/Base/Session/Typo3.php:
--------------------------------------------------------------------------------
1 | user = $user;
34 | }
35 |
36 |
37 | /**
38 | * Sets a list of key/value pairs.
39 | *
40 | * @param array $values Associative list of key/value pairs
41 | * @return \Aimeos\Base\Session\Iface Session instance for method chaining
42 | */
43 | public function apply( array $values ) : Iface
44 | {
45 | foreach( $values as $key => $value ) {
46 | $this->user->setAndSaveSessionData( $key, $value );
47 | }
48 |
49 | return $this;
50 | }
51 |
52 |
53 | /**
54 | * Remove the given key from the session.
55 | *
56 | * @param string $name Key of the requested value in the session
57 | * @return \Aimeos\Base\Session\Iface Session instance for method chaining
58 | */
59 | public function del( string $name ) : Iface
60 | {
61 | $this->user->setAndSaveSessionData( $name, null );
62 | return $this;
63 | }
64 |
65 |
66 | /**
67 | * Returns the value of the requested session key.
68 | *
69 | * If the returned value wasn't a string, it's decoded from its serialized
70 | * representation.
71 | *
72 | * @param string $name Key of the requested value in the session
73 | * @param mixed $default Value returned if requested key isn't found
74 | * @return mixed Value associated to the requested key
75 | */
76 | public function get( string $name, $default = null )
77 | {
78 | if( ( $value = $this->user->getSessionData( $name ) ) !== null ) {
79 | return $value;
80 | }
81 |
82 | return $default;
83 | }
84 |
85 |
86 | /**
87 | * Remove the list of keys from the session.
88 | *
89 | * @param array $names Keys to remove from the session
90 | * @return \Aimeos\Base\Session\Iface Session instance for method chaining
91 | */
92 | public function remove( array $names ) : Iface
93 | {
94 | foreach( $names as $name ) {
95 | $this->user->setAndSaveSessionData( $name, null );
96 | }
97 |
98 | return $this;
99 | }
100 |
101 |
102 | /**
103 | * Sets the value for the specified key.
104 | *
105 | * If the value isn't a string, it's encoded into a serialized representation
106 | * and decoded again when using the get() method.
107 | *
108 | * @param string $name Key to the value which should be stored in the session
109 | * @param mixed $value Value that should be associated with the given key
110 | * @return \Aimeos\Base\Session\Iface Session instance for method chaining
111 | */
112 | public function set( string $name, $value ) : Iface
113 | {
114 | $this->user->setAndSaveSessionData( $name, $value );
115 | return $this;
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/tests/Base/Cache/Typo3Test.php:
--------------------------------------------------------------------------------
1 | markTestSkipped( 'Class \\TYPO3\\CMS\\Core\\Cache\\Frontend\\FrontendInterface not found' );
23 | }
24 |
25 | $this->mock = $this->getMockBuilder( 'TYPO3\CMS\Core\Cache\Frontend\FrontendInterface' )->getMock();
26 | $this->object = new \Aimeos\Base\Cache\Typo3( $this->mock );
27 | }
28 |
29 |
30 | protected function tearDown() : void
31 | {
32 | unset( $this->mock, $this->object );
33 | }
34 |
35 |
36 | public function testClear()
37 | {
38 | $this->mock->expects( $this->once() )->method( 'flush' );
39 | $this->assertTrue( $this->object->clear() );
40 | }
41 |
42 |
43 | public function testClearWithSiteId()
44 | {
45 | $object = new \Aimeos\Base\Cache\Typo3( $this->mock );
46 |
47 | $this->mock->expects( $this->once() )->method( 'flush' );
48 | $this->assertTrue( $object->clear() );
49 | }
50 |
51 |
52 | public function testDelete()
53 | {
54 | $this->mock->expects( $this->once() )->method( 'remove' )->with( $this->equalTo( 'key' ) );
55 | $this->assertTrue( $this->object->delete( 'key' ) );
56 | }
57 |
58 |
59 | public function testDeleteMultiple()
60 | {
61 | $this->mock->expects( $this->exactly( 2 ) )->method( 'remove' )->with( $this->equalTo( 'key' ) );
62 | $this->assertTrue( $this->object->deleteMultiple( array( 'key', 'key' ) ) );
63 | }
64 |
65 |
66 | public function testDeleteByTags()
67 | {
68 | $this->mock->expects( $this->exactly( 2 ) )->method( 'flushByTag' )->with( $this->equalTo( 'tag' ) );
69 | $this->assertTrue( $this->object->deleteByTags( array( 'tag', 'tag' ) ) );
70 | }
71 |
72 |
73 | public function testGet()
74 | {
75 | $this->mock->expects( $this->once() )->method( 'get' )
76 | ->with( $this->equalTo( 'key' ) )->willReturn( 'value' );
77 |
78 | $this->assertEquals( 'value', $this->object->get( 'key', 'default' ) );
79 | }
80 |
81 |
82 | public function testGetMultiple()
83 | {
84 | $this->mock->expects( $this->exactly( 2 ) )->method( 'get' )
85 | ->willReturn( 'value' );
86 |
87 | $expected = array( 'key1' => 'value', 'key2' => 'value' );
88 | $this->assertEquals( $expected, $this->object->getMultiple( array( 'key1', 'key2' ) ) );
89 | }
90 |
91 |
92 | public function testHas()
93 | {
94 | $this->mock->expects( $this->once() )->method( 'has' )->willReturn( true );
95 | $this->assertTrue( $this->object->has( 'key' ) );
96 | }
97 |
98 |
99 | public function testSet()
100 | {
101 | $this->mock->expects( $this->once() )->method( 'set' )
102 | ->with(
103 | $this->equalTo( 'key' ), $this->equalTo( 'value' ),
104 | $this->equalTo( ['tag'] ), $this->greaterThan( 0 )
105 | );
106 |
107 | $this->assertTrue( $this->object->set( 'key', 'value', '2100-01-01 00:00:00', ['tag'] ) );
108 | }
109 |
110 |
111 | public function testSetMultiple()
112 | {
113 | $this->mock->expects( $this->once() )->method( 'set' )
114 | ->with(
115 | $this->equalTo( 'key' ), $this->equalTo( 'value' ),
116 | $this->equalTo( ['tag'] ), $this->greaterThan( 0 )
117 | );
118 |
119 | $expires = '2100-01-01 00:00:00';
120 | $this->assertTrue( $this->object->setMultiple( ['key' => 'value'], $expires, ['tag'] ) );
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/src/Base/View/Helper/Request/Typo3.php:
--------------------------------------------------------------------------------
1 | target = $target;
43 | $this->ip = ( isset( $server['REMOTE_ADDR'] ) ? $server['REMOTE_ADDR'] : null );
44 |
45 | $psr7request = $this->createRequest( $files, $query, $post, $cookies, $server );
46 |
47 | parent::__construct( $view, $psr7request );
48 | }
49 |
50 |
51 | /**
52 | * Returns the client IP address.
53 | *
54 | * @return string Client IP address
55 | */
56 | public function getClientAddress() : string
57 | {
58 | return $this->ip;
59 | }
60 |
61 |
62 | /**
63 | * Returns the current page or route name
64 | *
65 | * @return string|null Current page ID
66 | */
67 | public function getTarget() : ?string
68 | {
69 | return $this->target;
70 | }
71 |
72 |
73 | /**
74 | * Creates a PSR-7 compatible request
75 | *
76 | * @param array $files List of uploaded files like in $_FILES
77 | * @param array $query List of uploaded files like in $_GET
78 | * @param array $post List of uploaded files like in $_POST
79 | * @param array $cookies List of uploaded files like in $_COOKIES
80 | * @param array $server List of uploaded files like in $_SERVER
81 | * @return \Psr\Http\Message\ServerRequestInterface PSR-7 request object
82 | */
83 | protected function createRequest( array $files, array $query, array $post, array $cookies, array $server ) : \Psr\Http\Message\ServerRequestInterface
84 | {
85 | $psr17Factory = new \Nyholm\Psr7\Factory\Psr17Factory();
86 |
87 | $creator = new \Nyholm\Psr7Server\ServerRequestCreator(
88 | $psr17Factory, // ServerRequestFactory
89 | $psr17Factory, // UriFactory
90 | $psr17Factory, // UploadedFileFactory
91 | $psr17Factory // StreamFactory
92 | );
93 |
94 | if( !isset( $server['HTTP_HOST'] ) ) {
95 | $server['HTTP_HOST'] = 'localhost';
96 | }
97 |
98 | if( !isset( $server['REQUEST_METHOD'] ) ) {
99 | $server['REQUEST_METHOD'] = 'GET';
100 | }
101 |
102 | $headers = function_exists( 'getallheaders' ) ? getallheaders() : $creator::getHeadersFromServer( $server );
103 | $body = fopen( 'php://input', 'r' ) ?: null;
104 |
105 | $request = $creator->fromArrays( $server, $headers, $cookies, $query, $post, $files, $body );
106 | $psr7files = $request->getUploadedFiles();
107 |
108 | if( isset( $psr7files['ai'] ) ) {
109 | $request = $request->withUploadedFiles( $psr7files['ai'] );
110 | }
111 |
112 | return $request;
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/tests/Base/Mail/Message/Typo3Test.php:
--------------------------------------------------------------------------------
1 | markTestSkipped( 'Class TYPO3\\CMS\\Core\\Mail\\MailMessage not found' );
23 | }
24 |
25 | $this->mock = $this->getMockBuilder( 'TYPO3\\CMS\\Core\\Mail\\MailMessage' )
26 | ->disableOriginalConstructor()
27 | ->getMock();
28 |
29 | $this->object = new \Aimeos\Base\Mail\Message\Typo3( $this->mock, 'UTF-8' );
30 | }
31 |
32 |
33 | protected function tearDown() : void
34 | {
35 | unset( $this->object, $this->mock );
36 | }
37 |
38 |
39 | public function testFrom()
40 | {
41 | $this->mock->expects( $this->once() )->method( 'addFrom' );
42 |
43 | $result = $this->object->from( 'a@b', 'test' );
44 | $this->assertSame( $this->object, $result );
45 | }
46 |
47 |
48 | public function testTo()
49 | {
50 | $this->mock->expects( $this->once() )->method( 'addTo' );
51 |
52 | $result = $this->object->to( 'a@b', 'test' );
53 | $this->assertSame( $this->object, $result );
54 | }
55 |
56 |
57 | public function testCc()
58 | {
59 | $this->mock->expects( $this->once() )->method( 'addCc' );
60 |
61 | $result = $this->object->cc( 'a@b', 'test' );
62 | $this->assertSame( $this->object, $result );
63 | }
64 |
65 |
66 | public function testBcc()
67 | {
68 | $this->mock->expects( $this->once() )->method( 'addBcc' );
69 |
70 | $result = $this->object->bcc( 'a@b', 'test' );
71 | $this->assertSame( $this->object, $result );
72 | }
73 |
74 |
75 | public function testReplyTo()
76 | {
77 | $this->mock->expects( $this->once() )->method( 'addReplyTo' );
78 |
79 | $result = $this->object->replyTo( 'a@b', 'test' );
80 | $this->assertSame( $this->object, $result );
81 | }
82 |
83 |
84 | public function testSend()
85 | {
86 | $this->mock->expects( $this->once() )->method( 'send' );
87 | $this->assertSame( $this->object, $this->object->send() );
88 | }
89 |
90 |
91 | public function testSender()
92 | {
93 | $this->mock->expects( $this->once() )->method( 'setSender' );
94 |
95 | $result = $this->object->sender( 'a@b', 'test' );
96 | $this->assertSame( $this->object, $result );
97 | }
98 |
99 |
100 | public function testSubject()
101 | {
102 | $this->mock->expects( $this->once() )->method( 'setSubject' )
103 | ->with( $this->stringContains( 'test' ) );
104 |
105 | $result = $this->object->subject( 'test' );
106 | $this->assertSame( $this->object, $result );
107 | }
108 |
109 |
110 | public function testText()
111 | {
112 | $this->mock->expects( $this->once() )->method( 'text' )
113 | ->with( $this->stringContains( 'test' ) );
114 |
115 | $result = $this->object->text( 'test' );
116 | $this->assertSame( $this->object, $result );
117 | }
118 |
119 |
120 | public function testHtml()
121 | {
122 | $this->mock->expects( $this->once() )->method( 'html' )
123 | ->with( $this->stringContains( 'test' ) );
124 |
125 | $result = $this->object->html( 'test' );
126 | $this->assertSame( $this->object, $result );
127 | }
128 |
129 |
130 | public function testAttach()
131 | {
132 | $this->markTestIncomplete( 'Swift_Attachment::newInstance() is not testable' );
133 | }
134 |
135 |
136 | public function testEmbed()
137 | {
138 | $this->markTestIncomplete( 'Swift_EmbeddedFile::newInstance() is not testable' );
139 | }
140 |
141 |
142 | public function testObject()
143 | {
144 | $this->assertInstanceOf( 'TYPO3\\CMS\\Core\\Mail\\MailMessage', $this->object->object() );
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/config/mshop/customer.php:
--------------------------------------------------------------------------------
1 | array(
11 | 'typo3' => array(
12 | 'aggregate' => array(
13 | 'ansi' => '
14 | SELECT :keys, COUNT("val") AS "count"
15 | FROM (
16 | SELECT :acols, :val AS "val"
17 | FROM "fe_users" mcus
18 | :joins
19 | WHERE :cond
20 | GROUP BY mcus.uid, :cols, :val
21 | ORDER BY mcus.uid DESC
22 | OFFSET :start ROWS FETCH NEXT :size ROWS ONLY
23 | ) AS list
24 | GROUP BY :keys
25 | ',
26 | 'mysql' => '
27 | SELECT :keys, COUNT("val") AS "count"
28 | FROM (
29 | SELECT :acols, :val AS "val"
30 | FROM "fe_users" mcus
31 | :joins
32 | WHERE :cond
33 | GROUP BY mcus.uid, :cols, :val
34 | ORDER BY mcus.uid DESC
35 | LIMIT :size OFFSET :start
36 | ) AS list
37 | GROUP BY :keys
38 | '
39 | ),
40 | 'clear' => array(
41 | 'ansi' => '
42 | DELETE FROM "fe_users"
43 | WHERE :cond AND "siteid" LIKE ?
44 | ',
45 | ),
46 | 'delete' => array(
47 | 'ansi' => '
48 | DELETE FROM "fe_users"
49 | WHERE :cond AND ( "siteid" LIKE ? OR siteid = ? )
50 | ',
51 | ),
52 | 'insert' => array(
53 | 'ansi' => '
54 | INSERT INTO "fe_users" ( :names
55 | "name", "username", "gender", "company", "vatid",
56 | "title", "first_name", "last_name", "address", "zip", "city", "zone",
57 | "language", "telephone", "mobile", "email", "fax", "www", "longitude", "latitude",
58 | "date_of_birth", "disable", "password", "tstamp", "static_info_country",
59 | "usergroup", "pid", "editor", "siteid", "crdate"
60 | ) VALUES ( :values
61 | ?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?
62 | )
63 | ',
64 | ),
65 | 'update' => array(
66 | 'ansi' => '
67 | UPDATE "fe_users"
68 | SET :names
69 | "name" = ?, "username" = ?, "gender" = ?, "company" = ?, "vatid" = ?, "title" = ?,
70 | "first_name" = ?, "last_name" = ?, "address" = ?, "zip" = ?, "city" = ?, "zone" = ?,
71 | "language" = ?, "telephone" = ?, "mobile" = ?, "email" = ?, "fax" = ?, "www" = ?, "longitude" = ?,
72 | "latitude" = ?, "date_of_birth" = ?, "disable" = ?, "password" = ?, "tstamp" = ?,
73 | "static_info_country" = ?, "usergroup" = ?, "pid" = ?, "editor" = ?
74 | WHERE ( "siteid" LIKE ? OR siteid = ? ) AND "uid" = ?
75 | ',
76 | ),
77 | 'search' => array(
78 | 'ansi' => '
79 | SELECT :columns
80 | FROM "fe_users" as mcus
81 | :joins
82 | WHERE :cond AND mcus."deleted" = 0
83 | GROUP BY :group
84 | ORDER BY :order
85 | OFFSET :start ROWS FETCH NEXT :size ROWS ONLY
86 | ',
87 | 'mysql' => '
88 | SELECT :columns
89 | FROM "fe_users" as mcus
90 | :joins
91 | WHERE :cond AND mcus."deleted" = 0
92 | GROUP BY :group
93 | ORDER BY :order
94 | LIMIT :size OFFSET :start
95 | ',
96 | ),
97 | 'count' => array(
98 | 'ansi' => '
99 | SELECT COUNT(*) AS "count"
100 | FROM (
101 | SELECT mcus."uid"
102 | FROM "fe_users" mcus
103 | :joins
104 | WHERE :cond AND mcus."deleted" = 0
105 | GROUP BY mcus."uid"
106 | OFFSET 0 ROWS FETCH NEXT 10000 ROWS ONLY
107 | ) AS list
108 | ',
109 | 'mysql' => '
110 | SELECT COUNT(*) AS "count"
111 | FROM (
112 | SELECT mcus."uid"
113 | FROM "fe_users" mcus
114 | :joins
115 | WHERE :cond AND mcus."deleted" = 0
116 | GROUP BY mcus."uid"
117 | LIMIT 10000 OFFSET 0
118 | ) AS list
119 | ',
120 | ),
121 | 'newid' => array(
122 | 'db2' => 'SELECT IDENTITY_VAL_LOCAL()',
123 | 'mysql' => 'SELECT LAST_INSERT_ID()',
124 | 'oracle' => 'SELECT fe_users.CURRVAL FROM DUAL',
125 | 'pgsql' => 'SELECT lastval()',
126 | 'sqlite' => 'SELECT last_insert_rowid()',
127 | 'sqlsrv' => 'SELECT SCOPE_IDENTITY()',
128 | 'sqlanywhere' => 'SELECT @@IDENTITY',
129 | ),
130 | ),
131 | ),
132 | );
133 |
--------------------------------------------------------------------------------
/tests/MShop/Group/Manager/Typo3Test.php:
--------------------------------------------------------------------------------
1 | editor = $context->editor();
22 |
23 | $this->object = new \Aimeos\MShop\Group\Manager\Typo3( $context );
24 | }
25 |
26 |
27 | protected function tearDown() : void
28 | {
29 | unset( $this->object );
30 | }
31 |
32 |
33 | public function testClear()
34 | {
35 | $this->assertInstanceOf( \Aimeos\MShop\Common\Manager\Iface::class, $this->object->clear( array( -1 ) ) );
36 | }
37 |
38 |
39 | public function testCreateItem()
40 | {
41 | $item = $this->object->create();
42 | $this->assertInstanceOf( \Aimeos\MShop\Group\Item\Iface::class, $item );
43 | }
44 |
45 |
46 | public function testCreateSearch()
47 | {
48 | $this->assertInstanceOf( \Aimeos\Base\Criteria\Iface::class, $this->object->filter() );
49 | }
50 |
51 |
52 | public function testDeleteItems()
53 | {
54 | $this->assertInstanceOf( \Aimeos\MShop\Common\Manager\Iface::class, $this->object->delete( [-1] ) );
55 | }
56 |
57 |
58 | public function testGetSearchAttributes()
59 | {
60 | foreach( $this->object->getSearchAttributes() as $attribute ) {
61 | $this->assertInstanceOf( \Aimeos\Base\Criteria\Attribute\Iface::class, $attribute );
62 | }
63 | }
64 |
65 |
66 | public function testFindItem()
67 | {
68 | $item = $this->object->find( 'unitgroup' );
69 |
70 | $this->assertEquals( 'unitgroup', $item->getCode() );
71 | }
72 |
73 |
74 | public function testGetItem()
75 | {
76 | $item = $this->object->find( 'unitgroup' );
77 |
78 | $this->assertEquals( $item, $this->object->get( $item->getId() ) );
79 | }
80 |
81 |
82 | public function testSaveUpdateDeleteItem()
83 | {
84 | $item = $this->object->create();
85 | $item->setCode( 'unittest-group' );
86 |
87 | $resultSaved = $this->object->save( $item );
88 | $itemSaved = $this->object->get( $item->getId() );
89 |
90 | $itemExp = clone $itemSaved;
91 | $itemExp->setCode( 'unittest-group-2' );
92 |
93 | $resultUpd = $this->object->save( $itemExp );
94 | $itemUpd = $this->object->get( $itemExp->getId() );
95 |
96 | $this->object->delete( $itemSaved->getId() );
97 |
98 |
99 | $this->assertTrue( $item->getId() !== null );
100 | $this->assertEquals( $item->getId(), $itemSaved->getId() );
101 | $this->assertEquals( $item->getCode(), $itemSaved->getCode() );
102 | $this->assertEquals( $item->getLabel(), $itemSaved->getLabel() );
103 |
104 | $this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemSaved->getTimeCreated() );
105 | $this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemSaved->getTimeModified() );
106 |
107 | $this->assertEquals( $itemExp->getId(), $itemUpd->getId() );
108 | $this->assertEquals( $itemExp->getCode(), $itemUpd->getCode() );
109 | $this->assertEquals( $itemExp->getLabel(), $itemUpd->getLabel() );
110 |
111 | $this->assertEquals( $itemExp->getTimeCreated(), $itemUpd->getTimeCreated() );
112 | $this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemUpd->getTimeModified() );
113 |
114 | $this->assertInstanceOf( \Aimeos\MShop\Common\Item\Iface::class, $resultSaved );
115 | $this->assertInstanceOf( \Aimeos\MShop\Common\Item\Iface::class, $resultUpd );
116 |
117 | $this->expectException( \Aimeos\MShop\Exception::class );
118 | $this->object->get( $itemSaved->getId() );
119 | }
120 |
121 |
122 | public function testSearchItem()
123 | {
124 | $search = $this->object->filter();
125 | $search->setConditions( $search->compare( '==', 'group.label', 'Unitgroup' ) );
126 | $search->slice( 0, 1 );
127 |
128 | $total = 0;
129 | $results = $this->object->search( $search, [], $total );
130 |
131 | $this->assertEquals( 1, count( $results ) );
132 | $this->assertEquals( 1, $total );
133 | }
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/src/Base/View/Helper/Url/Typo3.php:
--------------------------------------------------------------------------------
1 | prefix = $uriBuilder->getArgumentPrefix();
42 | $this->uriBuilder = clone $uriBuilder;
43 | $this->fixed = $fixed;
44 | }
45 |
46 |
47 | /**
48 | * Returns the URL assembled from the given arguments.
49 | *
50 | * @param string|null $target Route or page which should be the target of the link (if any)
51 | * @param string|null $controller Name of the controller which should be part of the link (if any)
52 | * @param string|null $action Name of the action which should be part of the link (if any)
53 | * @param array $params Associative list of parameters that should be part of the URL
54 | * @param array $trailing Trailing URL parts that are not relevant to identify the resource (for pretty URLs)
55 | * @param array $config Additional configuration parameter per URL
56 | * @return string Complete URL that can be used in the template
57 | */
58 | public function transform( ?string $target = null, ?string $controller = null, ?string $action = null,
59 | array $params = [], array $trailing = [], array $config = [] ) : string
60 | {
61 | $locale = $this->getValue( $params, 'locale' );
62 |
63 | if( (bool) $this->getValue( $config, 'BE', false ) === false ) {
64 | $params['controller'] = $controller !== null ? ucfirst( $controller ) : null;
65 | $params['action'] = $action;
66 | }
67 |
68 | if( $this->prefix != '' && (bool) $this->getValue( $config, 'namespace', true ) === true ) {
69 | $params = [$this->prefix => $params];
70 | }
71 | $params += $this->fixed;
72 |
73 | if( (bool) $this->getValue( $config, 'BE', false ) === true ) {
74 | $params['controller'] = $controller !== null ? ucfirst( $controller ) : null;
75 | $params['action'] = $action;
76 | }
77 |
78 | if( ( $eid = $this->getValue( $config, 'eID' ) ) !== null ) {
79 | $params['eID'] = $eid;
80 | }
81 |
82 | if( $locale !== null && (bool) $this->getValue( $config, 'BE', false ) === false ) {
83 | $params['L'] = $locale;
84 | }
85 |
86 | $useCHash = (bool) $this->getValue( $config, 'chash', false );
87 |
88 | $this->uriBuilder->reset()
89 | ->setCreateAbsoluteUri( (bool) $this->getValue( $config, 'absoluteUri', false ) )
90 | ->setTargetPageType( (int) $this->getValue( $config, 'type', 0 ) )
91 | ->setNoCache( (bool) $this->getValue( $config, 'nocache', false ) )
92 | ->setFormat( (string) $this->getValue( $config, 'format', '' ) )
93 | ->setArguments( $this->sanitize( $params ) )
94 | ->setSection( join( '/', $trailing ) );
95 |
96 | if( $target ) {
97 | $this->uriBuilder->setTargetPageUid( (int) $target );
98 | }
99 |
100 | if( (bool) $this->getValue( $config, 'BE', false ) === true ) {
101 | return (string) $this->uriBuilder->buildBackendUri();
102 | }
103 |
104 | $url = (string) $this->uriBuilder->buildFrontendUri();
105 | return $useCHash ? $url : preg_replace( '/\&cHash=[0-9a-f]{32}/', '', $url ); // wokaround for bad TYPO3 behavior
106 | }
107 |
108 |
109 | /**
110 | * Returns the sanitized configuration values.
111 | *
112 | * @param array $config Associative list of key/value pairs
113 | * @param string $key Key of the value to retrieve
114 | * @param mixed $default Default value if value for key isn't found
115 | * @return mixed Configuration value for the given key or default value
116 | */
117 | protected function getValue( array $config, string $key, $default = null )
118 | {
119 | if( isset( $config[$key] ) ) {
120 | return $config[$key];
121 | }
122 |
123 | return $default;
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/tests/MShop/Customer/Manager/Lists/Type/Typo3Test.php:
--------------------------------------------------------------------------------
1 | editor = \TestHelper::context()->editor();
21 | $this->object = new \Aimeos\MShop\Customer\Manager\Lists\Type\Typo3( \TestHelper::context() );
22 | }
23 |
24 |
25 | protected function tearDown() : void
26 | {
27 | unset( $this->object );
28 | }
29 |
30 |
31 | public function testCreateItem()
32 | {
33 | $item = $this->object->create();
34 | $this->assertInstanceOf( \Aimeos\MShop\Type\Item\Iface::class, $item );
35 | }
36 |
37 |
38 | public function testGetItem()
39 | {
40 | $search = $this->object->filter()->slice( 0, 1 );
41 | $item = $this->object->search( $search )->first( new \RuntimeException( 'No list type item found' ) );
42 |
43 | $this->assertEquals( $item, $this->object->get( $item->getId() ) );
44 | }
45 |
46 |
47 | public function testSaveUpdateDeleteItem()
48 | {
49 | $search = $this->object->filter()->slice( 0, 1 );
50 | $item = $this->object->search( $search )->first( new \RuntimeException( 'No list type item found' ) );
51 |
52 | $item->setId( null );
53 | $item->setCode( 'unitTestInit' );
54 | $resultSaved = $this->object->save( $item );
55 | $itemSaved = $this->object->get( $item->getId() );
56 |
57 | $itemExp = clone $itemSaved;
58 | $itemExp->setCode( 'unitTestSave' );
59 | $resultUpd = $this->object->save( $itemExp );
60 | $itemUpd = $this->object->get( $itemExp->getId() );
61 |
62 | $this->object->delete( $itemSaved->getId() );
63 |
64 |
65 | $this->assertTrue( $item->getId() !== null );
66 | $this->assertEquals( $item->getId(), $itemSaved->getId() );
67 | $this->assertEquals( $item->getSiteId(), $itemSaved->getSiteId() );
68 | $this->assertEquals( $item->getCode(), $itemSaved->getCode() );
69 | $this->assertEquals( $item->getDomain(), $itemSaved->getDomain() );
70 | $this->assertEquals( $item->getLabel(), $itemSaved->getLabel() );
71 | $this->assertEquals( $item->getStatus(), $itemSaved->getStatus() );
72 |
73 | $this->assertEquals( $this->editor, $itemSaved->editor() );
74 | $this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemSaved->getTimeCreated() );
75 | $this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemSaved->getTimeModified() );
76 |
77 | $this->assertEquals( $itemExp->getId(), $itemUpd->getId() );
78 | $this->assertEquals( $itemExp->getSiteId(), $itemUpd->getSiteId() );
79 | $this->assertEquals( $itemExp->getCode(), $itemUpd->getCode() );
80 | $this->assertEquals( $itemExp->getDomain(), $itemUpd->getDomain() );
81 | $this->assertEquals( $itemExp->getLabel(), $itemUpd->getLabel() );
82 | $this->assertEquals( $itemExp->getStatus(), $itemUpd->getStatus() );
83 |
84 | $this->assertEquals( $this->editor, $itemUpd->editor() );
85 | $this->assertEquals( $itemExp->getTimeCreated(), $itemUpd->getTimeCreated() );
86 | $this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemUpd->getTimeModified() );
87 |
88 | $this->assertInstanceOf( \Aimeos\MShop\Common\Item\Iface::class, $resultSaved );
89 | $this->assertInstanceOf( \Aimeos\MShop\Common\Item\Iface::class, $resultUpd );
90 |
91 | $this->expectException( '\\Aimeos\\MShop\\Exception' );
92 | $this->object->get( $itemSaved->getId() );
93 | }
94 |
95 |
96 | public function testSearchItems()
97 | {
98 | $total = 0;
99 | $search = $this->object->filter();
100 |
101 | $expr = [];
102 | $expr[] = $search->compare( '!=', 'customer.lists.type.id', 0 );
103 | $expr[] = $search->compare( '!=', 'customer.lists.type.siteid', null );
104 | $expr[] = $search->compare( '==', 'customer.lists.type.code', 'default' );
105 | $expr[] = $search->compare( '==', 'customer.lists.type.domain', 'customer/lists' );
106 | $expr[] = $search->compare( '==', 'customer.lists.type.label', 'Standard' );
107 | $expr[] = $search->compare( '>=', 'customer.lists.type.position', 0 );
108 | $expr[] = $search->compare( '==', 'customer.lists.type.status', 1 );
109 | $expr[] = $search->compare( '>=', 'customer.lists.type.mtime', '1970-01-01 00:00:00' );
110 | $expr[] = $search->compare( '>=', 'customer.lists.type.ctime', '1970-01-01 00:00:00' );
111 | $expr[] = $search->compare( '==', 'customer.lists.type.editor', 'core' );
112 |
113 | $search->add( $search->and( $expr ) )->slice( 0, 1 );
114 | $results = $this->object->search( $search, [], $total );
115 |
116 | $this->assertEquals( 1, count( $results ) );
117 | $this->assertEquals( 1, $total );
118 |
119 | foreach( $results as $itemId => $item ) {
120 | $this->assertEquals( $itemId, $item->getId() );
121 | }
122 | }
123 |
124 | }
125 |
--------------------------------------------------------------------------------
/setup/default/schema/customer.php:
--------------------------------------------------------------------------------
1 | array(
11 |
12 | 'fe_users_address' => function( \Aimeos\Upscheme\Schema\Table $table ) {
13 |
14 | $table->engine = 'InnoDB';
15 |
16 | $table->id()->primary( 'pk_t3feuad_id' );
17 | $table->string( 'siteid' );
18 | $table->int( 'parentid' );
19 | $table->type()->default( 'delivery' );
20 | $table->string( 'company', 100 );
21 | $table->string( 'vatid', 32 );
22 | $table->string( 'salutation', 8 );
23 | $table->string( 'title', 64 );
24 | $table->string( 'firstname', 64 );
25 | $table->string( 'lastname', 64 );
26 | $table->string( 'address1', 200 );
27 | $table->string( 'address2', 200 );
28 | $table->string( 'address3', 200 );
29 | $table->string( 'postal', 16 );
30 | $table->string( 'city', 200 );
31 | $table->string( 'state', 200 );
32 | $table->string( 'langid', 5 )->null( true );
33 | $table->string( 'countryid', 2 )->null( true );
34 | $table->string( 'telephone', 32 );
35 | $table->string( 'telefax', 32 );
36 | $table->string( 'mobile', 32 )->default( '' );
37 | $table->string( 'email' );
38 | $table->string( 'website' );
39 | $table->float( 'longitude' )->null( true );
40 | $table->float( 'latitude' )->null( true );
41 | $table->date( 'birthday' )->null( true );
42 | $table->smallint( 'pos' );
43 | $table->meta();
44 |
45 | $table->index( ['langid', 'siteid'], 'idx_t3feuad_langid_sid' );
46 | $table->index( ['lastname', 'firstname'], 'idx_t3feuad_last_first' );
47 | $table->index( ['postal', 'address1'], 'idx_t3feuad_post_addr1' );
48 | $table->index( ['postal', 'city'], 'idx_t3feuad_post_ci' );
49 | $table->index( ['city'], 'idx_t3feuad_city' );
50 | $table->index( ['email'], 'idx_t3feuad_email' );
51 |
52 | $table->foreign( 'parentid', 'fe_users', 'uid', 'fk_t3feuad_pid' );
53 | },
54 |
55 | 'fe_users_list_type' => function( \Aimeos\Upscheme\Schema\Table $table ) {
56 |
57 | $table->engine = 'InnoDB';
58 |
59 | $table->id()->primary( 'pk_t3feulity_id' );
60 | $table->string( 'siteid' );
61 | $table->string( 'domain', 32 );
62 | $table->code();
63 | $table->string( 'label' );
64 | $table->i18n();
65 | $table->int( 'pos' )->default( 0 );
66 | $table->smallint( 'status' );
67 | $table->meta();
68 |
69 | $table->unique( ['domain', 'code', 'siteid'], 'unq_t3feulity_dom_code_sid' );
70 | $table->index( ['status', 'siteid', 'pos'], 'idx_t3feulity_status_sid_pos' );
71 | $table->index( ['label', 'siteid'], 'idx_t3feulity_label_sid' );
72 | $table->index( ['code', 'siteid'], 'idx_t3feulity_code_sid' );
73 | },
74 |
75 | 'fe_users_list' => function( \Aimeos\Upscheme\Schema\Table $table ) {
76 |
77 | $table->engine = 'InnoDB';
78 |
79 | $table->id()->primary( 'pk_t3feuli_id' );
80 | $table->string( 'siteid' );
81 | $table->int( 'parentid' );
82 | $table->string( 'key', 134 )->default( '' );
83 | $table->type( 'type' );
84 | $table->string( 'domain', 32 );
85 | $table->refid();
86 | $table->startend();
87 | $table->config();
88 | $table->int( 'pos' );
89 | $table->smallint( 'status' );
90 | $table->meta();
91 |
92 | $table->unique( ['parentid', 'domain', 'type', 'refid', 'siteid'], 'unq_t3feuli_pid_dm_ty_rid_sid' );
93 | $table->index( ['key', 'siteid'], 'idx_t3feuli_key_sid' );
94 |
95 | $table->foreign( 'parentid', 'fe_users', 'uid', 'fk_t3feuli_pid' );
96 | },
97 |
98 | 'fe_users_property_type' => function( \Aimeos\Upscheme\Schema\Table $table ) {
99 |
100 | $table->engine = 'InnoDB';
101 |
102 | $table->id()->primary( 'pk_t3feuprty_id' );
103 | $table->string( 'siteid' );
104 | $table->string( 'domain', 32 );
105 | $table->code();
106 | $table->string( 'label' );
107 | $table->i18n();
108 | $table->int( 'pos' )->default( 0 );
109 | $table->smallint( 'status' );
110 | $table->meta();
111 |
112 | $table->unique( ['domain', 'code', 'siteid'], 'unq_t3feuprty_dom_code_sid' );
113 | $table->index( ['status', 'siteid', 'pos'], 'idx_t3feuprty_status_sid_pos' );
114 | $table->index( ['label', 'siteid'], 'idx_t3feuprty_label_sid' );
115 | $table->index( ['code', 'siteid'], 'idx_t3feuprty_code_sid' );
116 | },
117 |
118 | 'fe_users_property' => function( \Aimeos\Upscheme\Schema\Table $table ) {
119 |
120 | $table->engine = 'InnoDB';
121 |
122 | $table->id()->primary( 'pk_t3feupr_id' );
123 | $table->string( 'siteid' );
124 | $table->int( 'parentid' );
125 | $table->string( 'key', 255 )->default( '' );
126 | $table->type();
127 | $table->string( 'langid', 5 )->null( true );
128 | $table->string( 'value' );
129 | $table->meta();
130 |
131 | $table->unique( ['parentid', 'type', 'langid', 'value', 'siteid'], 'unq_t3feupr_pid_ty_lid_val_sid' );
132 | $table->index( ['key', 'siteid'], 'idx_t3feupr_key_sid' );
133 |
134 | $table->foreign( 'parentid', 'fe_users', 'uid', 'fk_t3feupr_pid' );
135 | },
136 | ),
137 | );
138 |
--------------------------------------------------------------------------------
/setup/unittest/schema/customer.php:
--------------------------------------------------------------------------------
1 | array(
11 |
12 | 'fe_users' => function( \Aimeos\Upscheme\Schema\Table $table ) {
13 |
14 | $table->id( 'uid' )->unsigned( true )->primary( 'PRIMARY' );
15 | $table->string( 'siteid' )->default( '1.' );
16 | $table->int( 'pid' )->unsigned( true )->default( 0 );
17 | $table->int( 'deleted' )->length( 3 )->default( 0 );
18 | $table->int( 'hidden' )->length( 3 )->default( 0 );
19 | $table->int( 'disable' )->unsigned( true )->length( 3 )->default( 0 );
20 | $table->int( 'tstamp' )->unsigned( true )->default( 0 );
21 | $table->int( 'crdate' )->unsigned( true )->default( 0 );
22 | $table->int( 'cruser_id' )->unsigned( true )->default( 0 );
23 | $table->string( 'lockToDomain' )->length( 50 )->default( '' );
24 | $table->text( 'TSconfig' )->default( '' );
25 | $table->int( 'starttime' )->unsigned( true )->length( 11 )->default( 0 );
26 | $table->int( 'endtime' )->unsigned( true )->length( 11 )->default( 0 );
27 | $table->string( 'usergroup' )->null( true );
28 | $table->string( 'name' )->length( 100 )->default( '' );
29 | $table->text( 'uc' )->null( true );
30 | $table->string( 'username' )->length( 50 )->null( true );
31 | $table->string( 'password' )->length( 100 )->null( true );
32 | $table->string( 'first_name' )->length( 50 )->null( true );
33 | $table->string( 'middle_name' )->length( 50 )->null( true );
34 | $table->string( 'last_name' )->length( 50 )->null( true );
35 | $table->string( 'address' )->null( true );
36 | $table->string( 'telephone' )->length( 20 )->null( true );
37 | $table->string( 'fax' )->length( 20 )->null( true );
38 | $table->string( 'mobile', 32 )->default( '' );
39 | $table->string( 'email' )->length( 80 )->null( true );
40 | $table->string( 'title' )->length( 40 )->null( true );
41 | $table->string( 'city' )->length( 50 )->null( true );
42 | $table->string( 'www' )->length( 80 )->null( true );
43 | $table->string( 'company' )->length( 80 )->null( true );
44 | $table->string( 'vatid' )->length( 50 )->null( true );
45 | $table->string( 'zip' )->length( 20 )->default( '' );
46 | $table->string( 'country' )->length( 60 )->default( '' );
47 | $table->text( 'image', 255 )->null( true );
48 | $table->string( 'felogin_forgotHash' )->length( 80 )->null( true );
49 | $table->string( 'tx_extbase_type' )->null( true );
50 | $table->int( 'fe_cruser_id' )->unsigned( true )->default( 0 );
51 | $table->int( 'lastlogin' )->unsigned( true )->default( 0 );
52 | $table->int( 'is_online' )->unsigned( true )->default( 0 );
53 | $table->int( 'date_of_birth' )->unsigned( true )->default( 0 );
54 | $table->string( 'zone' )->length( 45 )->default( '' );
55 | $table->string( 'language' )->length( 2 )->default( '' );
56 | $table->string( 'cnum' )->length( 50 )->default( '' );
57 | $table->string( 'token' )->length( 32 )->default( '' );
58 | $table->int( 'gender' )->unsigned( true )->default( 99 );
59 | $table->int( 'status' )->unsigned( true )->default( 0 );
60 | $table->int( 'by_invitation' )->unsigned( true )->default( 0 );
61 | $table->int( 'module_sys_dmail_html' )->unsigned( true )->default( 0 );
62 | $table->int( 'terms_acknowledged' )->unsigned( true )->default( 0 );
63 | $table->text( 'tx_srfeuserregister_password' )->default( '' );
64 | $table->text( 'comments' )->default( '' );
65 | $table->text( 'felogin_redirectPid' )->length( 0xff )->default( '' );
66 | $table->string( 'static_info_country' )->length( 3 )->default( '' );
67 | $table->float( 'longitude' )->null( true )->default( null );
68 | $table->float( 'latitude' )->null( true )->default( null );
69 | $table->date( 'vdate' )->null( true );
70 | $table->string( 'editor' )->default( '' );
71 |
72 | $table->index( ['pid', 'username'], 'fe_users_parent' );
73 | $table->index( ['username'], 'fe_users_username' );
74 | $table->index( ['is_online'], 'fe_users_is_online' );
75 | },
76 |
77 | 'fe_groups' => function( \Aimeos\Upscheme\Schema\Table $table ) {
78 |
79 | $table->id( 'uid' )->unsigned( true )->primary( 'PRIMARY' );
80 | $table->int( 'pid' )->unsigned( true )->default( 0 );
81 | $table->int( 'deleted' )->length( 3 )->default( 0 );
82 | $table->int( 'hidden' )->length( 3 )->default( 0 );
83 | $table->int( 'tstamp' )->unsigned( true )->default( 0 );
84 | $table->int( 'crdate' )->unsigned( true )->default( 0 );
85 | $table->int( 'cruser_id' )->unsigned( true )->default( 0 );
86 | $table->string( 'title' )->length( 50 )->default( '' );
87 | $table->string( 'lockToDomain' )->length( 50 )->default( '' );
88 | $table->text( 'description' )->default( '' );
89 | $table->text( 'TSconfig' )->default( '' );
90 | $table->text( 'subgroup' )->length( 0xff )->default( '' );
91 | $table->text( 'felogin_redirectPid' )->length( 0xff )->null( true );
92 | $table->int( 'tx_phpunit_is_dummy_record' )->unsigned( true )->length( 1 )->default( 0 );
93 |
94 | $table->index( ['pid', 'deleted', 'hidden'], 'fe_groups_parent' );
95 | },
96 | ),
97 | );
98 |
--------------------------------------------------------------------------------
/tests/MShop/Customer/Manager/Property/Type/Typo3Test.php:
--------------------------------------------------------------------------------
1 | editor = $context->editor();
22 |
23 | $this->object = new \Aimeos\MShop\Customer\Manager\Property\Type\Typo3( $context );
24 | }
25 |
26 |
27 | protected function tearDown() : void
28 | {
29 | unset( $this->object );
30 | }
31 |
32 |
33 | public function testClear()
34 | {
35 | $this->assertInstanceOf( \Aimeos\MShop\Common\Manager\Iface::class, $this->object->clear( array( -1 ) ) );
36 | }
37 |
38 |
39 | public function testCreateItem()
40 | {
41 | $this->assertInstanceOf( \Aimeos\MShop\Type\Item\Iface::class, $this->object->create() );
42 | }
43 |
44 |
45 | public function testGetSearchAttributes()
46 | {
47 | foreach( $this->object->getSearchAttributes() as $attribute ) {
48 | $this->assertInstanceOf( '\\Aimeos\\Base\\Criteria\\Attribute\\Iface', $attribute );
49 | }
50 | }
51 |
52 |
53 | public function testGetItem()
54 | {
55 | $search = $this->object->filter()->slice( 0, 1 );
56 | $item = $this->object->search( $search )->first( new \RuntimeException( 'No list type item found' ) );
57 |
58 | $this->assertEquals( $item, $this->object->get( $item->getId() ) );
59 | }
60 |
61 |
62 | public function testSaveUpdateDeleteItem()
63 | {
64 | $search = $this->object->filter()->slice( 0, 1 );
65 | $item = $this->object->search( $search )->first( new \RuntimeException( 'No list type item found' ) );
66 |
67 | $item->setId( null );
68 | $item->setCode( 'unitTestSave' );
69 | $resultSaved = $this->object->save( $item );
70 | $itemSaved = $this->object->get( $item->getId() );
71 |
72 | $itemExp = clone $itemSaved;
73 | $itemExp->setCode( 'unitTestSave2' );
74 | $resultUpd = $this->object->save( $itemExp );
75 | $itemUpd = $this->object->get( $itemExp->getId() );
76 |
77 | $this->object->delete( $itemSaved->getId() );
78 |
79 |
80 | $this->assertTrue( $item->getId() !== null );
81 | $this->assertEquals( $item->getId(), $itemSaved->getId() );
82 | $this->assertEquals( $item->getSiteId(), $itemSaved->getSiteId() );
83 | $this->assertEquals( $item->getCode(), $itemSaved->getCode() );
84 | $this->assertEquals( $item->getDomain(), $itemSaved->getDomain() );
85 | $this->assertEquals( $item->getLabel(), $itemSaved->getLabel() );
86 | $this->assertEquals( $item->getStatus(), $itemSaved->getStatus() );
87 |
88 | $this->assertEquals( $this->editor, $itemSaved->editor() );
89 | $this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemSaved->getTimeCreated() );
90 | $this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemSaved->getTimeModified() );
91 |
92 | $this->assertEquals( $itemExp->getId(), $itemUpd->getId() );
93 | $this->assertEquals( $itemExp->getSiteId(), $itemUpd->getSiteId() );
94 | $this->assertEquals( $itemExp->getCode(), $itemUpd->getCode() );
95 | $this->assertEquals( $itemExp->getDomain(), $itemUpd->getDomain() );
96 | $this->assertEquals( $itemExp->getLabel(), $itemUpd->getLabel() );
97 | $this->assertEquals( $itemExp->getStatus(), $itemUpd->getStatus() );
98 |
99 | $this->assertEquals( $this->editor, $itemUpd->editor() );
100 | $this->assertEquals( $itemExp->getTimeCreated(), $itemUpd->getTimeCreated() );
101 | $this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemUpd->getTimeModified() );
102 |
103 | $this->assertInstanceOf( \Aimeos\MShop\Common\Item\Iface::class, $resultSaved );
104 | $this->assertInstanceOf( \Aimeos\MShop\Common\Item\Iface::class, $resultUpd );
105 |
106 | $this->expectException( '\\Aimeos\\MShop\\Exception' );
107 | $this->object->get( $itemSaved->getId() );
108 | }
109 |
110 |
111 | public function testSearchItems()
112 | {
113 | $total = 0;
114 | $search = $this->object->filter();
115 |
116 | $expr = [];
117 | $expr[] = $search->compare( '!=', 'customer.property.type.id', null );
118 | $expr[] = $search->compare( '!=', 'customer.property.type.siteid', null );
119 | $expr[] = $search->compare( '==', 'customer.property.type.domain', 'customer/property' );
120 | $expr[] = $search->compare( '==', 'customer.property.type.code', 'newsletter' );
121 | $expr[] = $search->compare( '>', 'customer.property.type.label', '' );
122 | $expr[] = $search->compare( '>=', 'customer.property.type.position', 0 );
123 | $expr[] = $search->compare( '==', 'customer.property.type.status', 1 );
124 | $expr[] = $search->compare( '>=', 'customer.property.type.mtime', '1970-01-01 00:00:00' );
125 | $expr[] = $search->compare( '>=', 'customer.property.type.ctime', '1970-01-01 00:00:00' );
126 | $expr[] = $search->compare( '==', 'customer.property.type.editor', 'core' );
127 |
128 | $search->add( $search->and( $expr ) );
129 | $results = $this->object->search( $search, [], $total );
130 |
131 | $this->assertEquals( 1, count( $results ) );
132 |
133 |
134 | $search = $this->object->filter();
135 | $conditions = array(
136 | $search->compare( '=~', 'customer.property.type.code', 'newsletter' ),
137 | $search->compare( '==', 'customer.property.type.editor', 'core' )
138 | );
139 | $search->add( $search->and( $conditions ) )->slice( 0, 1 );
140 | $items = $this->object->search( $search, [], $total );
141 |
142 | $this->assertEquals( 1, count( $items ) );
143 | $this->assertEquals( 1, $total );
144 |
145 | foreach( $items as $itemId => $item ) {
146 | $this->assertEquals( $itemId, $item->getId() );
147 | }
148 | }
149 |
150 |
151 | public function testGetSubManager()
152 | {
153 | $this->expectException( \LogicException::class );
154 | $this->object->getSubManager( 'unknown' );
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/tests/MShop/Customer/Manager/Property/Typo3Test.php:
--------------------------------------------------------------------------------
1 | editor = $context->editor();
22 |
23 | $this->object = new \Aimeos\MShop\Customer\Manager\Property\Typo3( $context );
24 | }
25 |
26 |
27 | protected function tearDown() : void
28 | {
29 | unset( $this->object );
30 | }
31 |
32 |
33 | public function testClear()
34 | {
35 | $this->assertInstanceOf( \Aimeos\MShop\Common\Manager\Iface::class, $this->object->clear( array( -1 ) ) );
36 | }
37 |
38 |
39 | public function testCreateItem()
40 | {
41 | $item = $this->object->create();
42 | $this->assertInstanceOf( '\\Aimeos\\MShop\\Common\\Item\\Property\\Iface', $item );
43 | }
44 |
45 |
46 | public function testSaveUpdateDeleteItem()
47 | {
48 | $search = $this->object->filter();
49 | $search->setConditions( $search->compare( '==', 'customer.property.editor', $this->editor ) );
50 |
51 | if( ( $item = $this->object->search( $search )->first() ) === null ) {
52 | throw new \RuntimeException( 'No property item found' );
53 | }
54 |
55 | $item->setId( null );
56 | $item->setLanguageId( 'en' );
57 | $resultSaved = $this->object->save( $item );
58 | $itemSaved = $this->object->get( $item->getId() );
59 |
60 | $itemExp = clone $itemSaved;
61 | $itemExp->setValue( 'unittest' );
62 | $resultUpd = $this->object->save( $itemExp );
63 | $itemUpd = $this->object->get( $itemExp->getId() );
64 |
65 | $this->object->delete( $itemSaved->getId() );
66 |
67 | $context = \TestHelper::context();
68 |
69 | $this->assertTrue( $item->getId() !== null );
70 | $this->assertEquals( $item->getId(), $itemSaved->getId() );
71 | $this->assertEquals( $item->getParentId(), $itemSaved->getParentId() );
72 | $this->assertEquals( $item->getSiteId(), $itemSaved->getSiteId() );
73 | $this->assertEquals( $item->getType(), $itemSaved->getType() );
74 | $this->assertEquals( $item->getLanguageId(), $itemSaved->getLanguageId() );
75 | $this->assertEquals( $item->getValue(), $itemSaved->getValue() );
76 |
77 | $this->assertEquals( $context->editor(), $itemSaved->editor() );
78 | $this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemSaved->getTimeCreated() );
79 | $this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemSaved->getTimeModified() );
80 |
81 | $this->assertEquals( $itemExp->getId(), $itemUpd->getId() );
82 | $this->assertEquals( $itemExp->getParentId(), $itemUpd->getParentId() );
83 | $this->assertEquals( $itemExp->getSiteId(), $itemUpd->getSiteId() );
84 | $this->assertEquals( $itemExp->getType(), $itemUpd->getType() );
85 | $this->assertEquals( $itemExp->getLanguageId(), $itemUpd->getLanguageId() );
86 | $this->assertEquals( $itemExp->getValue(), $itemUpd->getValue() );
87 |
88 | $this->assertEquals( $context->editor(), $itemUpd->editor() );
89 | $this->assertEquals( $itemExp->getTimeCreated(), $itemUpd->getTimeCreated() );
90 | $this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemUpd->getTimeModified() );
91 |
92 | $this->assertInstanceOf( \Aimeos\MShop\Common\Item\Iface::class, $resultSaved );
93 | $this->assertInstanceOf( \Aimeos\MShop\Common\Item\Iface::class, $resultUpd );
94 |
95 | $this->expectException( '\\Aimeos\\MShop\\Exception' );
96 | $this->object->get( $itemSaved->getId() );
97 | }
98 |
99 |
100 | public function testGetItem()
101 | {
102 | $search = $this->object->filter();
103 | $conditions = array(
104 | $search->compare( '~=', 'customer.property.value', '1' ),
105 | $search->compare( '==', 'customer.property.editor', $this->editor )
106 | );
107 | $search->setConditions( $search->and( $conditions ) );
108 |
109 | if( ( $item = $this->object->search( $search )->first() ) === null ) {
110 | throw new \RuntimeException( sprintf( 'No customer property item found for value "%1$s".', '1' ) );
111 | }
112 |
113 | $actual = $this->object->get( $item->getId() );
114 | $this->assertEquals( $item, $actual );
115 | }
116 |
117 |
118 | public function testGetSearchAttributes()
119 | {
120 | foreach( $this->object->getSearchAttributes() as $attribute ) {
121 | $this->assertInstanceOf( '\\Aimeos\\Base\\Criteria\\Attribute\\Iface', $attribute );
122 | }
123 | }
124 |
125 |
126 | public function testSearchItems()
127 | {
128 | $total = 0;
129 | $search = $this->object->filter();
130 |
131 | $expr = [];
132 | $expr[] = $search->compare( '!=', 'customer.property.id', null );
133 | $expr[] = $search->compare( '!=', 'customer.property.parentid', null );
134 | $expr[] = $search->compare( '!=', 'customer.property.siteid', null );
135 | $expr[] = $search->compare( '==', 'customer.property.type', 'newsletter' );
136 | $expr[] = $search->compare( '==', 'customer.property.languageid', null );
137 | $expr[] = $search->compare( '==', 'customer.property.value', '1' );
138 | $expr[] = $search->compare( '==', 'customer.property.editor', $this->editor );
139 |
140 | $search->setConditions( $search->and( $expr ) );
141 | $results = $this->object->search( $search, [], $total );
142 | $this->assertEquals( 1, count( $results ) );
143 | }
144 |
145 |
146 | public function testGetSubManager()
147 | {
148 | $this->assertInstanceOf( '\\Aimeos\\MShop\\Common\\Manager\\Iface', $this->object->getSubManager( 'type' ) );
149 | $this->assertInstanceOf( '\\Aimeos\\MShop\\Common\\Manager\\Iface', $this->object->getSubManager( 'type', 'Standard' ) );
150 |
151 | $this->expectException( \LogicException::class );
152 | $this->object->getSubManager( 'unknown' );
153 | }
154 |
155 |
156 | public function testGetSubManagerInvalidName()
157 | {
158 | $this->expectException( \LogicException::class );
159 | $this->object->getSubManager( 'type', 'unknown' );
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/tests/MShop/Customer/Manager/Lists/Typo3Test.php:
--------------------------------------------------------------------------------
1 | context = \TestHelper::context();
23 | $this->editor = $this->context->editor();
24 | $this->object = new \Aimeos\MShop\Customer\Manager\Lists\Typo3( \TestHelper::context() );
25 | }
26 |
27 |
28 | protected function tearDown() : void
29 | {
30 | unset( $this->object );
31 | }
32 |
33 |
34 | public function testCreateItem()
35 | {
36 | $item = $this->object->create();
37 | $this->assertInstanceOf( '\\Aimeos\\MShop\\Common\\Item\\Lists\\Iface', $item );
38 | }
39 |
40 |
41 | public function testGetItem()
42 | {
43 | $search = $this->object->filter()->slice( 0, 1 );
44 |
45 | if( ( $item = $this->object->search( $search )->first() ) === null ) {
46 | throw new \RuntimeException( 'No item found' );
47 | }
48 |
49 | $this->assertEquals( $item, $this->object->get( $item->getId() ) );
50 | }
51 |
52 |
53 | public function testSaveUpdateDeleteItem()
54 | {
55 | $search = $this->object->filter()->slice( 0, 1 );
56 |
57 | if( ( $item = $this->object->search( $search )->first() ) === null ) {
58 | throw new \RuntimeException( 'No item found' );
59 | }
60 |
61 | $item->setId( null );
62 | $item->setDomain( 'unittest' );
63 | $resultSaved = $this->object->save( $item );
64 | $itemSaved = $this->object->get( $item->getId() );
65 |
66 | $itemExp = clone $itemSaved;
67 | $itemExp->setDomain( 'unittest2' );
68 | $resultUpd = $this->object->save( $itemExp );
69 | $itemUpd = $this->object->get( $itemExp->getId() );
70 |
71 | $this->object->delete( $itemSaved->getId() );
72 |
73 |
74 | $this->assertTrue( $item->getId() !== null );
75 | $this->assertEquals( $item->getId(), $itemSaved->getId() );
76 | $this->assertEquals( $item->getSiteId(), $itemSaved->getSiteId() );
77 | $this->assertEquals( $item->getParentId(), $itemSaved->getParentId() );
78 | $this->assertEquals( $item->getType(), $itemSaved->getType() );
79 | $this->assertEquals( $item->getRefId(), $itemSaved->getRefId() );
80 | $this->assertEquals( $item->getDomain(), $itemSaved->getDomain() );
81 | $this->assertEquals( $item->getDateStart(), $itemSaved->getDateStart() );
82 | $this->assertEquals( $item->getDateEnd(), $itemSaved->getDateEnd() );
83 | $this->assertEquals( $item->getPosition(), $itemSaved->getPosition() );
84 | $this->assertEquals( $this->editor, $itemSaved->editor() );
85 | $this->assertStringStartsWith( date( 'Y-m-d', time() ), $itemSaved->getTimeCreated() );
86 | $this->assertStringStartsWith( date( 'Y-m-d', time() ), $itemSaved->getTimeModified() );
87 |
88 | $this->assertEquals( $this->editor, $itemSaved->editor() );
89 | $this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemSaved->getTimeCreated() );
90 | $this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemSaved->getTimeModified() );
91 |
92 | $this->assertEquals( $itemExp->getId(), $itemUpd->getId() );
93 | $this->assertEquals( $itemExp->getSiteId(), $itemUpd->getSiteId() );
94 | $this->assertEquals( $itemExp->getParentId(), $itemUpd->getParentId() );
95 | $this->assertEquals( $itemExp->getType(), $itemUpd->getType() );
96 | $this->assertEquals( $itemExp->getRefId(), $itemUpd->getRefId() );
97 | $this->assertEquals( $itemExp->getDomain(), $itemUpd->getDomain() );
98 | $this->assertEquals( $itemExp->getDateStart(), $itemUpd->getDateStart() );
99 | $this->assertEquals( $itemExp->getDateEnd(), $itemUpd->getDateEnd() );
100 | $this->assertEquals( $itemExp->getPosition(), $itemUpd->getPosition() );
101 |
102 | $this->assertEquals( $this->editor, $itemUpd->editor() );
103 | $this->assertEquals( $itemExp->getTimeCreated(), $itemUpd->getTimeCreated() );
104 | $this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemUpd->getTimeModified() );
105 |
106 | $this->assertInstanceOf( \Aimeos\MShop\Common\Item\Iface::class, $resultSaved );
107 | $this->assertInstanceOf( \Aimeos\MShop\Common\Item\Iface::class, $resultUpd );
108 |
109 | $this->expectException( '\\Aimeos\\MShop\\Exception' );
110 | $this->object->get( $itemSaved->getId() );
111 | }
112 |
113 |
114 | public function testSearchItems()
115 | {
116 | $total = 0;
117 | $search = $this->object->filter();
118 |
119 | $expr = [];
120 | $expr[] = $search->compare( '!=', 'customer.lists.id', null );
121 | $expr[] = $search->compare( '!=', 'customer.lists.siteid', null );
122 | $expr[] = $search->compare( '!=', 'customer.lists.parentid', null );
123 | $expr[] = $search->compare( '!=', 'customer.lists.key', null );
124 | $expr[] = $search->compare( '==', 'customer.lists.domain', 'text' );
125 | $expr[] = $search->compare( '==', 'customer.lists.type', 'default' );
126 | $expr[] = $search->compare( '>', 'customer.lists.refid', 0 );
127 | $expr[] = $search->compare( '==', 'customer.lists.datestart', '2010-01-01 00:00:00' );
128 | $expr[] = $search->compare( '==', 'customer.lists.dateend', '2098-01-01 00:00:00' );
129 | $expr[] = $search->compare( '!=', 'customer.lists.config', null );
130 | $expr[] = $search->compare( '>', 'customer.lists.position', 0 );
131 | $expr[] = $search->compare( '==', 'customer.lists.status', 1 );
132 | $expr[] = $search->compare( '>=', 'customer.lists.mtime', '1970-01-01 00:00:00' );
133 | $expr[] = $search->compare( '>=', 'customer.lists.ctime', '1970-01-01 00:00:00' );
134 | $expr[] = $search->compare( '==', 'customer.lists.editor', $this->editor );
135 |
136 | $search->setConditions( $search->and( $expr ) );
137 | $search->slice( 0, 2 );
138 | $results = $this->object->search( $search, [], $total );
139 | $this->assertEquals( 2, count( $results ) );
140 | $this->assertEquals( 3, $total );
141 |
142 | foreach( $results as $itemId => $item ) {
143 | $this->assertEquals( $itemId, $item->getId() );
144 | }
145 | }
146 |
147 |
148 | public function testSearchItemsAll()
149 | {
150 | //search without base criteria
151 | $search = $this->object->filter()->add( ['customer.lists.editor' => $this->editor] );
152 | $this->assertGreaterThanOrEqual( 5, count( $this->object->search( $search ) ) );
153 | }
154 |
155 |
156 | public function testSearchItemsBase()
157 | {
158 | //search with base criteria
159 | $search = $this->object->filter( true )->add( ['customer.lists.editor' => $this->editor] );
160 | $this->assertGreaterThanOrEqual( 5, count( $this->object->search( $search ) ) );
161 | }
162 |
163 |
164 | public function testGetSubManager()
165 | {
166 | $this->assertInstanceOf( '\\Aimeos\\MShop\\Common\\Manager\\Iface', $this->object->getSubManager( 'type' ) );
167 | $this->assertInstanceOf( '\\Aimeos\\MShop\\Common\\Manager\\Iface', $this->object->getSubManager( 'type', 'Typo3' ) );
168 |
169 | $this->expectException( \LogicException::class );
170 | $this->object->getSubManager( 'unknown' );
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/src/Base/Cache/Typo3.php:
--------------------------------------------------------------------------------
1 | object = $cache;
36 | }
37 |
38 |
39 | /**
40 | * Removes all expired cache entries.
41 | *
42 | * @inheritDoc
43 | *
44 | * @return bool True on success and false on failure
45 | */
46 | public function cleanup() : bool
47 | {
48 | $this->object->collectGarbage();
49 | return true;
50 | }
51 |
52 |
53 | /**
54 | * Removes all entries for the current site from the cache.
55 | *
56 | * @inheritDoc
57 | *
58 | * @return bool True on success and false on failure
59 | */
60 | public function clear() : bool
61 | {
62 | $this->object->flush();
63 | return true;
64 | }
65 |
66 |
67 | /**
68 | * Removes the cache entry identified by the given key.
69 | *
70 | * @inheritDoc
71 | *
72 | * @param string $key Key string that identifies the single cache entry
73 | * @return bool True if the item was successfully removed. False if there was an error
74 | * @throws \Psr\SimpleCache\InvalidArgumentException
75 | */
76 | public function delete( string $key ) : bool
77 | {
78 | $this->object->remove( $key );
79 | return true;
80 | }
81 |
82 |
83 | /**
84 | * Removes the cache entries identified by the given keys.
85 | *
86 | * @inheritDoc
87 | *
88 | * @param iterable $keys List of key strings that identify the cache entries that should be removed
89 | * @return bool True if the items were successfully removed. False if there was an error.
90 | * @throws \Psr\SimpleCache\InvalidArgumentException
91 | */
92 | public function deleteMultiple( iterable $keys ) : bool
93 | {
94 | foreach( $keys as $key ) {
95 | $this->object->remove( $key );
96 | }
97 |
98 | return true;
99 | }
100 |
101 |
102 | /**
103 | * Removes the cache entries identified by the given tags.
104 | *
105 | * @inheritDoc
106 | *
107 | * @param iterable $tags List of tag strings that are associated to one or
108 | * more cache entries that should be removed
109 | * @return bool True if the items were successfully removed. False if there was an error.
110 | * @throws \Psr\SimpleCache\InvalidArgumentException
111 | */
112 | public function deleteByTags( iterable $tags ) : bool
113 | {
114 | foreach( $tags as $tag ) {
115 | $this->object->flushByTag( $tag );
116 | }
117 |
118 | return true;
119 | }
120 |
121 |
122 | /**
123 | * Returns the value of the requested cache key.
124 | *
125 | * @inheritDoc
126 | *
127 | * @param string $key Path to the requested value like product/id/123
128 | * @param mixed $default Value returned if requested key isn't found
129 | * @return mixed Value associated to the requested key. If no value for the
130 | * key is found in the cache, the given default value is returned
131 | * @throws \Psr\SimpleCache\InvalidArgumentException
132 | */
133 | public function get( string $key, $default = null )
134 | {
135 | if( ( $entry = $this->object->get( $key ) ) !== false ) {
136 | return $entry;
137 | }
138 |
139 | return $default;
140 | }
141 |
142 |
143 | /**
144 | * Returns the cached values for the given cache keys.
145 | *
146 | * @inheritDoc
147 | *
148 | * @param iterable $keys List of key strings for the requested cache entries
149 | * @param mixed $default Default value to return for keys that do not exist
150 | * @return iterable A list of key => value pairs. Cache keys that do not exist or are stale will have $default as value.
151 | * @throws \Psr\SimpleCache\InvalidArgumentException
152 | */
153 | public function getMultiple( iterable $keys, $default = null ) : iterable
154 | {
155 | $result = [];
156 |
157 | foreach( $keys as $key )
158 | {
159 | if( ( $entry = $this->object->get( $key ) ) !== false ) {
160 | $result[$key] = $entry;
161 | } else {
162 | $result[$key] = $default;
163 | }
164 | }
165 |
166 | return $result;
167 | }
168 |
169 |
170 | /**
171 | * Determines whether an item is present in the cache.
172 | *
173 | * @inheritDoc
174 | *
175 | * @param string $key The cache item key
176 | * @return bool True if cache entry is available, false if not
177 | * @throws \Psr\SimpleCache\InvalidArgumentException
178 | */
179 | public function has( string $key ) : bool
180 | {
181 | return $this->object->has( $key );
182 | }
183 |
184 |
185 | /**
186 | * Sets the value for the given key in the cache.
187 | *
188 | * @inheritDoc
189 | *
190 | * @param string $key Key string for the given value like product/id/123
191 | * @param mixed $value Value string that should be stored for the given key
192 | * @param \DateInterval|int|string|null $expires Date interval object,
193 | * date/time string in "YYYY-MM-DD HH:mm:ss" format or as integer TTL value
194 | * when the cache entry will expiry
195 | * @param iterable $tags List of tag strings that should be assoicated to the cache entry
196 | * @return bool True on success and false on failure.
197 | * @throws \Psr\SimpleCache\InvalidArgumentException
198 | */
199 | public function set( string $key, $value, $expires = null, iterable $tags = [] ) : bool
200 | {
201 | if( $expires instanceof \DateInterval ) {
202 | $expires = date_create()->add( $expires )->getTimestamp() - time();
203 | } elseif( is_string( $expires ) ) {
204 | $expires = date_create( $expires )->getTimestamp() - time();
205 | } elseif( is_numeric( $expires ) ) {
206 | $expires = (int) max( min( $expires, 2147483647 ), 0 );
207 | }
208 |
209 | $tagList = [];
210 |
211 | foreach( $tags as $tag ) {
212 | $tagList[] = $tag;
213 | }
214 |
215 | $this->object->set( $key, $value, $tagList, $expires );
216 | return true;
217 | }
218 |
219 |
220 | /**
221 | * Adds or overwrites the given key/value pairs in the cache, which is much
222 | * more efficient than setting them one by one using the set() method.
223 | *
224 | * @inheritDoc
225 | *
226 | * @param iterable $pairs Associative list of key/value pairs. Both must be a string
227 | * @param \DateInterval|int|string|null $expires Date interval object,
228 | * date/time string in "YYYY-MM-DD HH:mm:ss" format or as integer TTL value
229 | * when the cache entry will expiry
230 | * @param iterable $tags List of tags that should be associated to the cache entries
231 | * @return bool True on success and false on failure.
232 | * @throws \Psr\SimpleCache\InvalidArgumentException
233 | */
234 | public function setMultiple( iterable $pairs, $expires = null, iterable $tags = [] ) : bool
235 | {
236 | foreach( $pairs as $key => $value ) {
237 | $this->set( $key, $value, $expires, $tags );
238 | }
239 |
240 | return true;
241 | }
242 | }
243 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
167 |
--------------------------------------------------------------------------------
/tests/Base/View/Helper/Url/Typo3Test.php:
--------------------------------------------------------------------------------
1 | markTestSkipped( 'TYPO3 UriBuilder not available' );
22 | }
23 |
24 | $this->view = new \Aimeos\Base\View\Standard();
25 | }
26 |
27 |
28 | protected function tearDown() : void
29 | {
30 | unset( $this->view );
31 | }
32 |
33 |
34 | public function testTransform()
35 | {
36 | $mock = $this->getMockBuilder( 'TYPO3\\CMS\\Extbase\\Mvc\\Web\\Routing\\UriBuilder' )
37 | ->onlyMethods( ['buildFrontendUri'] )
38 | ->disableOriginalConstructor()
39 | ->getMock();
40 |
41 | $mock->expects( $this->once() )->method( 'buildFrontendUri' );
42 |
43 | $fixed = ['site' => 'unittest'];
44 | $object = new \Aimeos\Base\View\Helper\Url\Typo3( $this->view, $mock, $fixed );
45 |
46 | $this->assertEquals( '', $object->transform() );
47 | }
48 |
49 |
50 | public function testTransformAbsolute()
51 | {
52 | $mock = $this->getMockBuilder( 'TYPO3\\CMS\\Extbase\\Mvc\\Web\\Routing\\UriBuilder' )
53 | ->onlyMethods( ['setCreateAbsoluteUri', 'buildFrontendUri'] )
54 | ->disableOriginalConstructor()
55 | ->getMock();
56 |
57 | $mock->expects( $this->once() )->method( 'setCreateAbsoluteUri' )
58 | ->with( $this->equalTo( true ) )->willReturn( $mock );
59 |
60 | $mock->expects( $this->once() )->method( 'buildFrontendUri' )->willReturn( '' );
61 |
62 | $object = new \Aimeos\Base\View\Helper\Url\Typo3( $this->view, $mock, [] );
63 |
64 | $config = ['absoluteUri' => 1];
65 | $this->assertEquals( '', $object->transform( null, null, null, [], [], $config ) );
66 | }
67 |
68 |
69 | public function testTransformNocache()
70 | {
71 | $mock = $this->getMockBuilder( 'TYPO3\\CMS\\Extbase\\Mvc\\Web\\Routing\\UriBuilder' )
72 | ->onlyMethods( ['setNoCache', 'buildFrontendUri'] )
73 | ->disableOriginalConstructor()
74 | ->getMock();
75 |
76 | $mock->expects( $this->once() )->method( 'setNoCache' )
77 | ->with( $this->equalTo( true ) )->willReturn( $mock );
78 |
79 | $mock->expects( $this->once() )->method( 'buildFrontendUri' )->willReturn( '' );
80 |
81 | $object = new \Aimeos\Base\View\Helper\Url\Typo3( $this->view, $mock, [] );
82 |
83 | $config = ['nocache' => 1];
84 | $this->assertEquals( '', $object->transform( null, null, null, [], [], $config ) );
85 | }
86 |
87 |
88 | public function testTransformType()
89 | {
90 | $mock = $this->getMockBuilder( 'TYPO3\\CMS\\Extbase\\Mvc\\Web\\Routing\\UriBuilder' )
91 | ->onlyMethods( ['setTargetPageType', 'buildFrontendUri'] )
92 | ->disableOriginalConstructor()
93 | ->getMock();
94 |
95 | $mock->expects( $this->once() )->method( 'setTargetPageType' )
96 | ->with( $this->equalTo( 123 ) )->willReturn( $mock );
97 |
98 | $mock->expects( $this->once() )->method( 'buildFrontendUri' )->willReturn( '' );
99 |
100 | $object = new \Aimeos\Base\View\Helper\Url\Typo3( $this->view, $mock, [] );
101 |
102 | $config = ['type' => 123];
103 | $this->assertEquals( '', $object->transform( null, null, null, [], [], $config ) );
104 | }
105 |
106 |
107 | public function testTransformFormat()
108 | {
109 | $mock = $this->getMockBuilder( 'TYPO3\\CMS\\Extbase\\Mvc\\Web\\Routing\\UriBuilder' )
110 | ->onlyMethods( ['setFormat', 'buildFrontendUri'] )
111 | ->disableOriginalConstructor()
112 | ->getMock();
113 |
114 | $mock->expects( $this->once() )->method( 'setFormat' )
115 | ->with( $this->equalTo( 'xml' ) )->willReturn( $mock );
116 |
117 | $mock->expects( $this->once() )->method( 'buildFrontendUri' )->willReturn( '' );
118 |
119 | $object = new \Aimeos\Base\View\Helper\Url\Typo3( $this->view, $mock, [] );
120 |
121 | $config = ['format' => 'xml'];
122 | $this->assertEquals( '', $object->transform( null, null, null, [], [], $config ) );
123 | }
124 |
125 |
126 | public function testTransformEID()
127 | {
128 | $mock = $this->getMockBuilder( 'TYPO3\\CMS\\Extbase\\Mvc\\Web\\Routing\\UriBuilder' )
129 | ->onlyMethods( ['setArguments', 'buildFrontendUri'] )
130 | ->disableOriginalConstructor()
131 | ->getMock();
132 |
133 | $param = ['eID' => 123, 'controller' => '', 'action' => null];
134 |
135 | $mock->expects( $this->once() )->method( 'setArguments' )
136 | ->with( $this->equalTo( $param ) )->willReturn( $mock );
137 |
138 | $mock->expects( $this->once() )->method( 'buildFrontendUri' )->willReturn( '' );
139 |
140 | $object = new \Aimeos\Base\View\Helper\Url\Typo3( $this->view, $mock, [] );
141 |
142 | $config = ['eID' => 123];
143 | $this->assertEquals( '', $object->transform( null, null, null, [], [], $config ) );
144 | }
145 |
146 |
147 | public function testTransformLocale()
148 | {
149 | $mock = $this->getMockBuilder( 'TYPO3\\CMS\\Extbase\\Mvc\\Web\\Routing\\UriBuilder' )
150 | ->onlyMethods( ['setArguments', 'buildFrontendUri'] )
151 | ->disableOriginalConstructor()
152 | ->getMock();
153 |
154 | $param = ['L' => 'de', 'controller' => '', 'action' => null, 'locale' => 'de'];
155 |
156 | $mock->expects( $this->once() )->method( 'setArguments' )
157 | ->with( $this->equalTo( $param ) )->willReturn( $mock );
158 |
159 | $mock->expects( $this->once() )->method( 'buildFrontendUri' )->willReturn( '' );
160 |
161 | $object = new \Aimeos\Base\View\Helper\Url\Typo3( $this->view, $mock, [] );
162 |
163 | $params = ['locale' => 'de'];
164 | $this->assertEquals( '', $object->transform( null, null, null, $params ) );
165 | }
166 |
167 |
168 | public function testTransformBackend()
169 | {
170 | $mock = $this->getMockBuilder( 'TYPO3\\CMS\\Extbase\\Mvc\\Web\\Routing\\UriBuilder' )
171 | ->onlyMethods( ['buildBackendUri'] )
172 | ->disableOriginalConstructor()
173 | ->getMock();
174 |
175 | $mock->expects( $this->once() )->method( 'buildBackendUri' );
176 |
177 | $object = new \Aimeos\Base\View\Helper\Url\Typo3( $this->view, $mock, ['site' => 'unittest'] );
178 |
179 | $params = ['test' => 'my/value'];
180 | $this->assertEquals( '', $object->transform( null, null, null, $params, [], ['BE' => 1] ) );
181 | }
182 |
183 |
184 | public function testTransformParams()
185 | {
186 | $mock = $this->getMockBuilder( 'TYPO3\\CMS\\Extbase\\Mvc\\Web\\Routing\\UriBuilder' )
187 | ->onlyMethods( ['buildFrontendUri'] )
188 | ->disableOriginalConstructor()
189 | ->getMock();
190 |
191 | $mock->expects( $this->once() )->method( 'buildFrontendUri' );
192 |
193 | $object = new \Aimeos\Base\View\Helper\Url\Typo3( $this->view, $mock, ['site' => 'unittest'] );
194 |
195 | $params = ['test' => 'my/value'];
196 | $this->assertEquals( '', $object->transform( null, null, null, $params ) );
197 | }
198 |
199 |
200 | public function testTransformNoNamespace()
201 | {
202 | $mock = $this->getMockBuilder( 'TYPO3\\CMS\\Extbase\\Mvc\\Web\\Routing\\UriBuilder' )
203 | ->onlyMethods( ['buildFrontendUri', 'getArgumentPrefix'] )
204 | ->disableOriginalConstructor()
205 | ->getMock();
206 |
207 | $mock->expects( $this->once() )->method( 'buildFrontendUri' );
208 | $mock->expects( $this->once() )->method( 'getArgumentPrefix' )->willReturn( 'ai' );
209 |
210 | $object = new \Aimeos\Base\View\Helper\Url\Typo3( $this->view, $mock, ['site' => 'unittest'] );
211 |
212 | $params = ['test' => 'my/value'];
213 | $config = ['namespace' => false];
214 | $this->assertEquals( '', $object->transform( null, null, null, $params, [], $config ) );
215 | }
216 |
217 |
218 | public function testTransformUnchangedOriginalUriBuilder()
219 | {
220 | $mock = $this->getMockBuilder( 'TYPO3\\CMS\\Extbase\\Mvc\\Web\\Routing\\UriBuilder' )
221 | ->onlyMethods( ['reset', 'buildFrontendUri'] )
222 | ->disableOriginalConstructor()
223 | ->getMock();
224 |
225 | $mock->expects( $this->once() )->method( 'reset' )->willReturn( $mock );
226 | $mock->expects( $this->once() )->method( 'buildFrontendUri' )->willReturn( '' );
227 |
228 | $object = new \Aimeos\Base\View\Helper\Url\Typo3( $this->view, $mock, [] );
229 |
230 | $mock->expects( $this->never() )->method( 'reset' );
231 | $this->assertEquals( '', $object->transform( null, null, null, [], [], [] ) );
232 | }
233 | }
234 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | # PHP CircleCI 2.0 configuration file
2 | #
3 | # Check https://circleci.com/docs/2.0/language-php/ for more details
4 | #
5 | version: 2.1
6 |
7 | jobs:
8 | "php81-mysql":
9 | docker:
10 | - image: aimeos/ci-php:8.1
11 | - image: mysql:latest
12 | environment:
13 | MYSQL_ROOT_PASSWORD: rootpw
14 | MYSQL_DATABASE: aimeos
15 | MYSQL_USER: aimeos
16 | MYSQL_PASSWORD: aimeos
17 | steps:
18 | - checkout
19 | - run: git clone --depth=50 --branch=master https://github.com/aimeos/aimeos-core ../aimeos-core
20 | - run: cd .. && mv project aimeos-core/ext/ai-typo3 && mv aimeos-core project && cd project
21 | - restore_cache:
22 | keys:
23 | - php81-{{ checksum "composer.json" }}
24 | - run: composer req --no-plugins --no-update "nyholm/psr7-server:^1.0" "nyholm/psr7:^1.2" "symfony/mailer:^6.4" "typo3/cms-core:^12.4"
25 | - run: composer update -n --no-plugins --prefer-dist
26 | - save_cache:
27 | key: php81-{{ checksum "composer.json" }}
28 | paths: [./vendor]
29 | - run: echo " array( 'adapter' => 'mysql', 'host' => '127.0.0.1', 'port' => 3306, 'database' => 'aimeos', 'username' => 'aimeos', 'password' => 'aimeos', 'limit' => 2, 'opt-persistent' => false, 'stmt' => array( \"SET SESSIOn sort_buffer_size=2097144; SET NAMES 'utf8'; SET SESSION sql_mode='ANSI'\" ) ), 'fs' => array( 'adapter' => 'Standard', 'basedir' => '.' ), 'mq' => array( 'adapter' => 'Standard', 'db' => 'db' ) );" > config/resource.php
30 | - run: for i in `seq 1 10`; do nc -z 127.0.0.1 3306 && echo OK && exit 0; echo -n .; sleep 1; done
31 | - run: ./vendor/bin/phing -Ddir=ext/ai-typo3 setup testext
32 |
33 | "php82-mysql":
34 | docker:
35 | - image: aimeos/ci-php:8.2
36 | - image: mysql:latest
37 | environment:
38 | MYSQL_ROOT_PASSWORD: rootpw
39 | MYSQL_DATABASE: aimeos
40 | MYSQL_USER: aimeos
41 | MYSQL_PASSWORD: aimeos
42 | steps:
43 | - checkout
44 | - run: git clone --depth=50 --branch=master https://github.com/aimeos/aimeos-core ../aimeos-core
45 | - run: cd .. && mv project aimeos-core/ext/ai-typo3 && mv aimeos-core project && cd project
46 | - restore_cache:
47 | keys:
48 | - php82-{{ checksum "composer.json" }}
49 | - run: composer req --no-plugins --no-update "nyholm/psr7-server:^1.0" "nyholm/psr7:^1.2" "symfony/mailer:^7.0" "typo3/cms-core:^12.4"
50 | - run: composer update -n --no-plugins --prefer-dist
51 | - save_cache:
52 | key: php82-{{ checksum "composer.json" }}
53 | paths: [./vendor]
54 | - run: echo " array( 'adapter' => 'mysql', 'host' => '127.0.0.1', 'port' => 3306, 'database' => 'aimeos', 'username' => 'aimeos', 'password' => 'aimeos', 'limit' => 2, 'opt-persistent' => false, 'stmt' => array( \"SET SESSIOn sort_buffer_size=2097144; SET NAMES 'utf8'; SET SESSION sql_mode='ANSI'\" ) ), 'fs' => array( 'adapter' => 'Standard', 'basedir' => '.' ), 'mq' => array( 'adapter' => 'Standard', 'db' => 'db' ) );" > config/resource.php
55 | - run: for i in `seq 1 10`; do nc -z 127.0.0.1 3306 && echo OK && exit 0; echo -n .; sleep 1; done
56 | - run: ./vendor/bin/phing -Ddir=ext/ai-typo3 setup coverageext
57 | - run: ./vendor/bin/php-coveralls --root_dir ext/ai-typo3 -o coveralls.json -vvv -x tests/coverage.xml
58 |
59 | "php83-mysql":
60 | docker:
61 | - image: aimeos/ci-php:8.3
62 | - image: mysql:latest
63 | environment:
64 | MYSQL_ROOT_PASSWORD: rootpw
65 | MYSQL_DATABASE: aimeos
66 | MYSQL_USER: aimeos
67 | MYSQL_PASSWORD: aimeos
68 | steps:
69 | - checkout
70 | - run: git clone --depth=50 --branch=master https://github.com/aimeos/aimeos-core ../aimeos-core
71 | - run: cd .. && mv project aimeos-core/ext/ai-typo3 && mv aimeos-core project && cd project
72 | - restore_cache:
73 | keys:
74 | - php83-{{ checksum "composer.json" }}
75 | - run: composer req --no-plugins --no-update "nyholm/psr7-server:^1.0" "nyholm/psr7:^1.2" "symfony/mailer:^7.0" "typo3/cms-core:^12.4"
76 | - run: composer update -n --no-plugins --prefer-dist
77 | - save_cache:
78 | key: php83-{{ checksum "composer.json" }}
79 | paths: [./vendor]
80 | - run: echo " array( 'adapter' => 'mysql', 'host' => '127.0.0.1', 'port' => 3306, 'database' => 'aimeos', 'username' => 'aimeos', 'password' => 'aimeos', 'limit' => 2, 'opt-persistent' => false, 'stmt' => array( \"SET SESSIOn sort_buffer_size=2097144; SET NAMES 'utf8'; SET SESSION sql_mode='ANSI'\" ) ), 'fs' => array( 'adapter' => 'Standard', 'basedir' => '.' ), 'mq' => array( 'adapter' => 'Standard', 'db' => 'db' ) );" > config/resource.php
81 | - run: for i in `seq 1 10`; do nc -z 127.0.0.1 3306 && echo OK && exit 0; echo -n .; sleep 1; done
82 | - run: ./vendor/bin/phing -Ddir=ext/ai-typo3 setup testext
83 |
84 | "php84-mysql":
85 | docker:
86 | - image: aimeos/ci-php:8.4
87 | - image: mysql:latest
88 | environment:
89 | MYSQL_ROOT_PASSWORD: rootpw
90 | MYSQL_DATABASE: aimeos
91 | MYSQL_USER: aimeos
92 | MYSQL_PASSWORD: aimeos
93 | steps:
94 | - checkout
95 | - run: git clone --depth=50 --branch=master https://github.com/aimeos/aimeos-core ../aimeos-core
96 | - run: cd .. && mv project aimeos-core/ext/ai-typo3 && mv aimeos-core project && cd project
97 | - restore_cache:
98 | keys:
99 | - php84-{{ checksum "composer.json" }}
100 | - run: composer req --no-plugins --no-update "nyholm/psr7-server:^1.0" "nyholm/psr7:^1.2" "symfony/mailer:^7.0" "typo3/cms-core:^12.4"
101 | - run: composer update -n --no-plugins --prefer-dist
102 | - save_cache:
103 | key: php84-{{ checksum "composer.json" }}
104 | paths: [./vendor]
105 | - run: echo " array( 'adapter' => 'mysql', 'host' => '127.0.0.1', 'port' => 3306, 'database' => 'aimeos', 'username' => 'aimeos', 'password' => 'aimeos', 'limit' => 2, 'opt-persistent' => false, 'stmt' => array( \"SET SESSIOn sort_buffer_size=2097144; SET NAMES 'utf8'; SET SESSION sql_mode='ANSI'\" ) ), 'fs' => array( 'adapter' => 'Standard', 'basedir' => '.' ), 'mq' => array( 'adapter' => 'Standard', 'db' => 'db' ) );" > config/resource.php
106 | - run: for i in `seq 1 10`; do nc -z 127.0.0.1 3306 && echo OK && exit 0; echo -n .; sleep 1; done
107 | - run: ./vendor/bin/phing -Ddir=ext/ai-typo3 setup testext
108 |
109 | "php85-mysql":
110 | docker:
111 | - image: aimeos/ci-php:8.5
112 | - image: mysql:latest
113 | environment:
114 | MYSQL_ROOT_PASSWORD: rootpw
115 | MYSQL_DATABASE: aimeos
116 | MYSQL_USER: aimeos
117 | MYSQL_PASSWORD: aimeos
118 | steps:
119 | - checkout
120 | - run: git clone --depth=50 --branch=master https://github.com/aimeos/aimeos-core ../aimeos-core
121 | - run: cd .. && mv project aimeos-core/ext/ai-typo3 && mv aimeos-core project && cd project
122 | - restore_cache:
123 | keys:
124 | - php85-{{ checksum "composer.json" }}
125 | - run: composer req --no-plugins --no-update "nyholm/psr7-server:^1.0" "nyholm/psr7:^1.2" "symfony/mailer:^7.0" "typo3/cms-core:^12.4"
126 | - run: composer update -n --no-plugins --prefer-dist
127 | - save_cache:
128 | key: php85-{{ checksum "composer.json" }}
129 | paths: [./vendor]
130 | - run: echo " array( 'adapter' => 'mysql', 'host' => '127.0.0.1', 'port' => 3306, 'database' => 'aimeos', 'username' => 'aimeos', 'password' => 'aimeos', 'limit' => 2, 'opt-persistent' => false, 'stmt' => array( \"SET SESSIOn sort_buffer_size=2097144; SET NAMES 'utf8'; SET SESSION sql_mode='ANSI'\" ) ), 'fs' => array( 'adapter' => 'Standard', 'basedir' => '.' ), 'mq' => array( 'adapter' => 'Standard', 'db' => 'db' ) );" > config/resource.php
131 | - run: for i in `seq 1 10`; do nc -z 127.0.0.1 3306 && echo OK && exit 0; echo -n .; sleep 1; done
132 | - run: ./vendor/bin/phing -Ddir=ext/ai-typo3 setup testext
133 |
134 | workflows:
135 | version: 2
136 | unittest:
137 | jobs:
138 | - "php81-mysql"
139 | - "php82-mysql"
140 | - "php83-mysql"
141 | - "php84-mysql"
142 | - "php85-mysql"
--------------------------------------------------------------------------------
/tests/MShop/Customer/Manager/Address/Typo3Test.php:
--------------------------------------------------------------------------------
1 | editor = \TestHelper::context()->editor();
21 | $this->object = new \Aimeos\MShop\Customer\Manager\Address\Typo3( \TestHelper::context() );
22 | }
23 |
24 |
25 | protected function tearDown() : void
26 | {
27 | unset( $this->object );
28 | }
29 |
30 |
31 | public function testGetSearchAttributes()
32 | {
33 | foreach( $this->object->getSearchAttributes() as $attribute )
34 | {
35 | $this->assertInstanceOf( '\\Aimeos\\Base\\Criteria\\Attribute\\Iface', $attribute );
36 | }
37 | }
38 |
39 |
40 | public function testCreateItem()
41 | {
42 | $this->assertInstanceOf( \Aimeos\MShop\Customer\Item\Address\Iface::class, $this->object->create() );
43 | }
44 |
45 |
46 | public function testGetItem()
47 | {
48 | $search = $this->object->filter()->slice( 0, 1 );
49 | $search->setConditions( $search->compare( '~=', 'customer.address.company', 'Example company' ) );
50 |
51 | if( ( $item = $this->object->search( $search )->first() ) === null ) {
52 | throw new \RuntimeException( 'No address item found' );
53 | }
54 |
55 | $this->assertEquals( $item, $this->object->get( $item->getId() ) );
56 | }
57 |
58 |
59 | public function testSaveUpdateDeleteItem()
60 | {
61 | $search = $this->object->filter()->slice( 0, 1 );
62 | $search->setConditions( $search->compare( '~=', 'customer.address.company', 'Example company' ) );
63 |
64 | if( ( $item = $this->object->search( $search )->first() ) === null ) {
65 | throw new \RuntimeException( 'No address item found' );
66 | }
67 |
68 | $item->setId( null );
69 | $resultSaved = $this->object->save( $item );
70 | $itemSaved = $this->object->get( $item->getId() );
71 |
72 | $itemExp = clone $itemSaved;
73 | $itemExp->setCompany( 'unitTest' );
74 | $resultUpd = $this->object->save( $itemExp );
75 | $itemUpd = $this->object->get( $itemExp->getId() );
76 |
77 | $this->object->delete( $item->getId() );
78 |
79 |
80 | $this->assertTrue( $item->getId() !== null );
81 | $this->assertEquals( $item->getId(), $itemSaved->getId() );
82 | $this->assertEquals( $item->getSiteId(), $itemSaved->getSiteId() );
83 | $this->assertEquals( $item->getParentId(), $itemSaved->getParentId() );
84 | $this->assertEquals( $item->getSalutation(), $itemSaved->getSalutation() );
85 | $this->assertEquals( $item->getType(), $itemSaved->getType() );
86 | $this->assertEquals( $item->getCompany(), $itemSaved->getCompany() );
87 | $this->assertEquals( $item->getVatID(), $itemSaved->getVatID() );
88 | $this->assertEquals( $item->getTitle(), $itemSaved->getTitle() );
89 | $this->assertEquals( $item->getFirstname(), $itemSaved->getFirstname() );
90 | $this->assertEquals( $item->getLastname(), $itemSaved->getLastname() );
91 | $this->assertEquals( $item->getAddress1(), $itemSaved->getAddress1() );
92 | $this->assertEquals( $item->getAddress2(), $itemSaved->getAddress2() );
93 | $this->assertEquals( $item->getAddress3(), $itemSaved->getAddress3() );
94 | $this->assertEquals( $item->getPostal(), $itemSaved->getPostal() );
95 | $this->assertEquals( $item->getCity(), $itemSaved->getCity() );
96 | $this->assertEquals( $item->getState(), $itemSaved->getState() );
97 | $this->assertEquals( $item->getLanguageId(), $itemSaved->getLanguageId() );
98 | $this->assertEquals( $item->getCountryId(), $itemSaved->getCountryId() );
99 | $this->assertEquals( $item->getTelephone(), $itemSaved->getTelephone() );
100 | $this->assertEquals( $item->getMobile(), $itemSaved->getMobile() );
101 | $this->assertEquals( $item->getEMail(), $itemSaved->getEMail() );
102 | $this->assertEquals( $item->getTelefax(), $itemSaved->getTelefax() );
103 | $this->assertEquals( $item->getWebsite(), $itemSaved->getWebsite() );
104 | $this->assertEquals( $item->getLongitude(), $itemSaved->getLongitude() );
105 | $this->assertEquals( $item->getLatitude(), $itemSaved->getLatitude() );
106 | $this->assertEquals( $item->getBirthday(), $itemSaved->getBirthday() );
107 | $this->assertEquals( $item->getPosition(), $itemSaved->getPosition() );
108 | $this->assertEquals( $item->editor(), $itemSaved->editor() );
109 |
110 | $this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemSaved->getTimeCreated() );
111 | $this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemSaved->getTimeModified() );
112 |
113 | $this->assertEquals( $itemExp->getId(), $itemUpd->getId() );
114 | $this->assertEquals( $itemExp->getSiteId(), $itemUpd->getSiteId() );
115 | $this->assertEquals( $itemExp->getParentId(), $itemUpd->getParentId() );
116 | $this->assertEquals( $itemExp->getType(), $itemUpd->getType() );
117 | $this->assertEquals( $itemExp->getSalutation(), $itemUpd->getSalutation() );
118 | $this->assertEquals( $itemExp->getCompany(), $itemUpd->getCompany() );
119 | $this->assertEquals( $itemExp->getVatID(), $itemUpd->getVatID() );
120 | $this->assertEquals( $itemExp->getTitle(), $itemUpd->getTitle() );
121 | $this->assertEquals( $itemExp->getFirstname(), $itemUpd->getFirstname() );
122 | $this->assertEquals( $itemExp->getLastname(), $itemUpd->getLastname() );
123 | $this->assertEquals( $itemExp->getAddress1(), $itemUpd->getAddress1() );
124 | $this->assertEquals( $itemExp->getAddress2(), $itemUpd->getAddress2() );
125 | $this->assertEquals( $itemExp->getAddress3(), $itemUpd->getAddress3() );
126 | $this->assertEquals( $itemExp->getPostal(), $itemUpd->getPostal() );
127 | $this->assertEquals( $itemExp->getCity(), $itemUpd->getCity() );
128 | $this->assertEquals( $itemExp->getState(), $itemUpd->getState() );
129 | $this->assertEquals( $itemExp->getLanguageId(), $itemUpd->getLanguageId() );
130 | $this->assertEquals( $itemExp->getCountryId(), $itemUpd->getCountryId() );
131 | $this->assertEquals( $itemExp->getTelephone(), $itemUpd->getTelephone() );
132 | $this->assertEquals( $itemExp->getMobile(), $itemUpd->getMobile() );
133 | $this->assertEquals( $itemExp->getEMail(), $itemUpd->getEMail() );
134 | $this->assertEquals( $itemExp->getTelefax(), $itemUpd->getTelefax() );
135 | $this->assertEquals( $itemExp->getWebsite(), $itemUpd->getWebsite() );
136 | $this->assertEquals( $itemExp->getLongitude(), $itemUpd->getLongitude() );
137 | $this->assertEquals( $itemExp->getLatitude(), $itemUpd->getLatitude() );
138 | $this->assertEquals( $itemExp->getBirthday(), $itemUpd->getBirthday() );
139 | $this->assertEquals( $itemExp->getPosition(), $itemUpd->getPosition() );
140 | $this->assertEquals( $itemExp->editor(), $itemUpd->editor() );
141 |
142 | $this->assertEquals( $itemExp->getTimeCreated(), $itemUpd->getTimeCreated() );
143 | $this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemUpd->getTimeModified() );
144 |
145 | $this->assertInstanceOf( \Aimeos\MShop\Common\Item\Iface::class, $resultSaved );
146 | $this->assertInstanceOf( \Aimeos\MShop\Common\Item\Iface::class, $resultUpd );
147 |
148 | $this->expectException( '\\Aimeos\\MShop\\Exception' );
149 | $this->object->get( $item->getId() );
150 | }
151 |
152 |
153 | public function testCreateSearch()
154 | {
155 | $this->assertInstanceOf( '\\Aimeos\\Base\\Criteria\\Iface', $this->object->filter() );
156 | }
157 |
158 |
159 | public function testSearchItem()
160 | {
161 | $search = $this->object->filter();
162 |
163 | $conditions = array(
164 | $search->compare( '!=', 'customer.address.id', null ),
165 | $search->compare( '!=', 'customer.address.parentid', null ),
166 | $search->compare( '==', 'customer.address.type', 'delivery' ),
167 | $search->compare( '==', 'customer.address.company', 'Example company' ),
168 | $search->compare( '==', 'customer.address.vatid', 'DE999999999' ),
169 | $search->compare( '==', 'customer.address.salutation', 'mr' ),
170 | $search->compare( '==', 'customer.address.title', 'Dr' ),
171 | $search->compare( '==', 'customer.address.firstname', 'Our' ),
172 | $search->compare( '==', 'customer.address.lastname', 'Unittest' ),
173 | $search->compare( '==', 'customer.address.address1', 'Pickhuben' ),
174 | $search->compare( '==', 'customer.address.address2', '2-4' ),
175 | $search->compare( '==', 'customer.address.address3', '' ),
176 | $search->compare( '==', 'customer.address.postal', '20457' ),
177 | $search->compare( '==', 'customer.address.city', 'Hamburg' ),
178 | $search->compare( '==', 'customer.address.state', 'Hamburg' ),
179 | $search->compare( '==', 'customer.address.countryid', 'DE' ),
180 | $search->compare( '==', 'customer.address.languageid', 'de' ),
181 | $search->compare( '==', 'customer.address.telephone', '055544332211' ),
182 | $search->compare( '==', 'customer.address.telefax', '055544332212' ),
183 | $search->compare( '==', 'customer.address.mobile', '055544332213' ),
184 | $search->compare( '==', 'customer.address.email', 'test@example.com' ),
185 | $search->compare( '==', 'customer.address.website', 'www.example.com' ),
186 | $search->compare( '==', 'customer.address.longitude', '10.0' ),
187 | $search->compare( '==', 'customer.address.latitude', '50.0' ),
188 | $search->compare( '==', 'customer.address.birthday', '2000-01-01' ),
189 | $search->compare( '>=', 'customer.address.mtime', '1970-01-01 00:00:00' ),
190 | $search->compare( '>=', 'customer.address.ctime', '1970-01-01 00:00:00' ),
191 | $search->compare( '==', 'customer.address.editor', $this->editor ),
192 | );
193 | $search->setConditions( $search->and( $conditions ) );
194 | $this->assertEquals( 1, count( $this->object->search( $search ) ) );
195 | }
196 |
197 |
198 | public function testSearchItemTotal()
199 | {
200 | $total = 0;
201 | $search = $this->object->filter();
202 |
203 | $conditions = array(
204 | $search->compare( '~=', 'customer.address.company', 'Example company' ),
205 | $search->compare( '==', 'customer.address.editor', $this->editor )
206 | );
207 |
208 | $search->setConditions( $search->and( $conditions ) );
209 | $search->slice( 0, 2 );
210 |
211 | $results = $this->object->search( $search, [], $total );
212 |
213 | $this->assertEquals( 2, count( $results ) );
214 | $this->assertEquals( 3, $total );
215 |
216 | foreach( $results as $id => $item ) {
217 | $this->assertEquals( $id, $item->getId() );
218 | }
219 | }
220 |
221 |
222 | public function testGetSubManager()
223 | {
224 | $this->expectException( \LogicException::class );
225 | $this->object->getSubManager( 'unknown' );
226 | }
227 |
228 |
229 | public function testGetSubManagerInvalidName()
230 | {
231 | $this->expectException( \LogicException::class );
232 | $this->object->getSubManager( 'address', 'unknown' );
233 | }
234 | }
235 |
--------------------------------------------------------------------------------
/src/Base/Mail/Message/Typo3.php:
--------------------------------------------------------------------------------
1 | charset = $charset;
36 | $this->object = $object;
37 | }
38 |
39 |
40 | /**
41 | * Adds a source e-mail address of the message.
42 | *
43 | * @param string $email Source e-mail address
44 | * @param string|null $name Name of the user sending the e-mail or null for no name
45 | * @return \Aimeos\Base\Mail\Message\Iface Message object
46 | */
47 | public function from( string $email, ?string $name = null ) : Iface
48 | {
49 | if( $email )
50 | {
51 | $class = '\Symfony\Component\Mime\Email';
52 |
53 | if( class_exists( $class ) && $this->object instanceof $class ) {
54 | $this->object->addFrom( new \Symfony\Component\Mime\Address( $email, (string) $name ) );
55 | } else {
56 | $this->object->addFrom( $email, $name );
57 | }
58 | }
59 |
60 | return $this;
61 | }
62 |
63 |
64 | /**
65 | * Adds a destination e-mail address of the target user mailbox.
66 | *
67 | * @param string $email Destination address of the target mailbox
68 | * @param string|null $name Name of the user owning the target mailbox or null for no name
69 | * @return \Aimeos\Base\Mail\Message\Iface Message object
70 | */
71 | public function to( string $email, ?string $name = null ) : Iface
72 | {
73 | if( $email )
74 | {
75 | $class = '\Symfony\Component\Mime\Email';
76 |
77 | if( class_exists( $class ) && $this->object instanceof $class ) {
78 | $this->object->addTo( new \Symfony\Component\Mime\Address( $email, (string) $name ) );
79 | } else {
80 | $this->object->addTo( $email, $name );
81 | }
82 | }
83 |
84 | return $this;
85 | }
86 |
87 |
88 | /**
89 | * Adds a destination e-mail address for a copy of the message.
90 | *
91 | * @param string $email Destination address for a copy
92 | * @param string|null $name Name of the user owning the target mailbox or null for no name
93 | * @return \Aimeos\Base\Mail\Message\Iface Message object
94 | */
95 | public function cc( string $email, ?string $name = null ) : Iface
96 | {
97 | if( $email )
98 | {
99 | $class = '\Symfony\Component\Mime\Email';
100 |
101 | if( class_exists( $class ) && $this->object instanceof $class ) {
102 | $this->object->addCc( new \Symfony\Component\Mime\Address( $email, (string) $name ) );
103 | } else {
104 | $this->object->addCc( $email, $name );
105 | }
106 | }
107 |
108 | return $this;
109 | }
110 |
111 |
112 | /**
113 | * Adds a destination e-mail address for a hidden copy of the message.
114 | *
115 | * @param array|string $email Destination address for a hidden copy
116 | * @return \Aimeos\Base\Mail\Message\Iface Message object
117 | */
118 | public function bcc( $email ) : Iface
119 | {
120 | if( !empty( $email ) )
121 | {
122 | $class = '\Symfony\Component\Mime\Email';
123 |
124 | foreach( (array) $email as $addr )
125 | {
126 | if( class_exists( $class ) && $this->object instanceof $class ) {
127 | $this->object->addBcc( new \Symfony\Component\Mime\Address( $addr ) );
128 | } else {
129 | $this->object->addBcc( $addr );
130 | }
131 | }
132 | }
133 |
134 | return $this;
135 | }
136 |
137 |
138 | /**
139 | * Adds the return e-mail address for the message.
140 | *
141 | * @param string $email E-mail address which should receive all replies
142 | * @param string|null $name Name of the user which should receive all replies or null for no name
143 | * @return \Aimeos\Base\Mail\Message\Iface Message object
144 | */
145 | public function replyTo( string $email, ?string $name = null ) : Iface
146 | {
147 | if( $email )
148 | {
149 | $class = '\Symfony\Component\Mime\Email';
150 |
151 | if( class_exists( $class ) && $this->object instanceof $class ) {
152 | $this->object->addReplyTo( new \Symfony\Component\Mime\Address( $email, (string) $name ) );
153 | } else {
154 | $this->object->addReplyTo( $email, $name );
155 | }
156 | }
157 |
158 | return $this;
159 | }
160 |
161 |
162 | /**
163 | * Adds a custom header to the message.
164 | *
165 | * @param string $name Name of the custom e-mail header
166 | * @param string $value Text content of the custom e-mail header
167 | * @return \Aimeos\Base\Mail\Message\Iface Message object
168 | */
169 | public function header( string $name, string $value ) : Iface
170 | {
171 | if( $name )
172 | {
173 | $class = '\Symfony\Component\Mime\Email';
174 |
175 | if( class_exists( $class ) && $this->object instanceof $class ) {
176 | $this->object->getHeaders()->add( new \Symfony\Component\Mime\Header\UnstructuredHeader( $name, $value ) );
177 | } else {
178 | $this->object->getHeaders()->addTextHeader( $name, $value );
179 | }
180 | }
181 |
182 | return $this;
183 | }
184 |
185 |
186 | /**
187 | * Sends the e-mail message to the mail server.
188 | *
189 | * @return \Aimeos\Base\Mail\Message\Iface Message object
190 | */
191 | public function send() : Iface
192 | {
193 | $this->object->send();
194 | return $this;
195 | }
196 |
197 |
198 | /**
199 | * Sets the e-mail address and name of the sender of the message (higher precedence than "From").
200 | *
201 | * @param string $email Source e-mail address
202 | * @param string|null $name Name of the user who sent the message or null for no name
203 | * @return \Aimeos\Base\Mail\Message\Iface Message object
204 | */
205 | public function sender( string $email, ?string $name = null ) : Iface
206 | {
207 | if( $email )
208 | {
209 | $class = '\Symfony\Component\Mime\Email';
210 |
211 | if( class_exists( $class ) && $this->object instanceof $class ) {
212 | $this->object->setSender( new \Symfony\Component\Mime\Address( $email, (string) $name ) );
213 | } else {
214 | $this->object->setSender( $email, $name );
215 | }
216 | }
217 |
218 | return $this;
219 | }
220 |
221 |
222 | /**
223 | * Sets the subject of the message.
224 | *
225 | * @param string $subject Subject of the message
226 | * @return \Aimeos\Base\Mail\Message\Iface Message object
227 | */
228 | public function subject( string $subject ) : Iface
229 | {
230 | if( $subject )
231 | {
232 | $class = '\Symfony\Component\Mime\Email';
233 |
234 | if( class_exists( $class ) && $this->object instanceof $class ) {
235 | $this->object->setSubject( $subject );
236 | } else {
237 | $this->object->setSubject( $subject );
238 | }
239 | }
240 |
241 | return $this;
242 | }
243 |
244 |
245 | /**
246 | * Sets the text body of the message.
247 | *
248 | * @param string $message Text body of the message
249 | * @return \Aimeos\Base\Mail\Message\Iface Message object
250 | */
251 | public function text( string $message ) : Iface
252 | {
253 | if( $message )
254 | {
255 | $class = '\Symfony\Component\Mime\Email';
256 |
257 | if( class_exists( $class ) && $this->object instanceof $class ) {
258 | $this->object->text( $message, $this->charset );
259 | } elseif( class_exists( '\Swift_Mailer' ) ) {
260 | $this->object->setBody( $message );
261 | }
262 | }
263 |
264 | return $this;
265 | }
266 |
267 |
268 | /**
269 | * Sets the HTML body of the message.
270 | *
271 | * @param string $message HTML body of the message
272 | * @return \Aimeos\Base\Mail\Message\Iface Message object
273 | */
274 | public function html( string $message ) : Iface
275 | {
276 | if( $message )
277 | {
278 | $class = '\Symfony\Component\Mime\Email';
279 |
280 | if( class_exists( $class ) && $this->object instanceof $class ) {
281 | $this->object->html( $message, $this->charset );
282 | } elseif( class_exists( '\Swift_Mailer' ) ) {
283 | $this->object->addPart( $message, 'text/html' );
284 | }
285 | }
286 |
287 | return $this;
288 | }
289 |
290 |
291 | /**
292 | * Adds an attachment to the message.
293 | *
294 | * @param string|null $data Binary or string @author nose
295 | * @param string|null $filename Name of the attached file (or null if inline disposition is used)
296 | * @param string|null $mimetype Mime type of the attachment (e.g. "text/plain", "application/octet-stream", etc.)
297 | * @param string $disposition Type of the disposition ("attachment" or "inline")
298 | * @return \Aimeos\Base\Mail\Message\Iface Message object
299 | */
300 | public function attach( ?string $data, ?string $filename = null, ?string $mimetype = null, string $disposition = 'attachment' ) : Iface
301 | {
302 | if( $data )
303 | {
304 | $class = '\Symfony\Component\Mime\Email';
305 | $mimetype = $mimetype ?: (new \finfo( FILEINFO_MIME_TYPE ))->buffer( $data );
306 | $filename = $filename ?: md5( $data );
307 |
308 | if( class_exists( $class ) && $this->object instanceof $class )
309 | {
310 | $this->object->attach( $data, $filename, $mimetype );
311 | }
312 | elseif( class_exists( '\Swift_Attachment' ) )
313 | {
314 | $part = \Swift_Attachment::newInstance( $data, $filename, $mimetype );
315 | $part->setDisposition( $disposition );
316 | $this->object->attach( $part );
317 | }
318 | else
319 | {
320 | throw new \RuntimeException( 'Symfony mailer or Swiftmailer package missing' );
321 | }
322 | }
323 |
324 | return $this;
325 | }
326 |
327 |
328 | /**
329 | * Embeds an attachment into the message and returns its reference.
330 | *
331 | * @param string|null $data Binary or string
332 | * @param string|null $filename Name of the attached file
333 | * @param string|null $mimetype Mime type of the attachment (e.g. "text/plain", "application/octet-stream", etc.)
334 | * @return string Content ID for referencing the attachment in the HTML body
335 | */
336 | public function embed( ?string $data, ?string $filename = null, ?string $mimetype = null ) : string
337 | {
338 | if( $data )
339 | {
340 | $class = '\Symfony\Component\Mime\Email';
341 | $mimetype = $mimetype ?: (new \finfo( FILEINFO_MIME_TYPE ))->buffer( $data );
342 | $filename = $filename ?: md5( $data );
343 |
344 | if( class_exists( $class ) && $this->object instanceof $class )
345 | {
346 | $this->object->embed( $data, $filename, $mimetype );
347 | return 'cid:' . $filename;
348 | }
349 | elseif( class_exists( '\Swift_EmbeddedFile' ) )
350 | {
351 | $part = \Swift_EmbeddedFile::newInstance( $data, $filename, $mimetype );
352 | return $this->object->embed( $part );
353 | }
354 | else
355 | {
356 | throw new \RuntimeException( 'Symfony mailer or Swiftmailer package missing' );
357 | }
358 | }
359 |
360 | return '';
361 | }
362 |
363 |
364 | /**
365 | * Returns the internal TYPO3 mail message object.
366 | *
367 | * @return \TYPO3\CMS\Core\Mail\MailMessage TYPO3 mail message object
368 | */
369 | public function object() : \TYPO3\CMS\Core\Mail\MailMessage
370 | {
371 | return $this->object;
372 | }
373 |
374 |
375 | /**
376 | * Clones the internal objects.
377 | */
378 | public function __clone()
379 | {
380 | $this->object = clone $this->object;
381 | }
382 | }
383 |
--------------------------------------------------------------------------------
/tests/MShop/Customer/Manager/Typo3Test.php:
--------------------------------------------------------------------------------
1 | context = \TestHelper::context();
22 | $this->context->config()->set( 'mshop/customer/manager/typo3/pid-default', 999999 );
23 |
24 | $this->object = new \Aimeos\MShop\Customer\Manager\Typo3( $this->context );
25 | $this->object = new \Aimeos\MShop\Common\Manager\Decorator\Lists( $this->object, $this->context );
26 | $this->object = new \Aimeos\MShop\Common\Manager\Decorator\Property( $this->object, $this->context );
27 | $this->object = new \Aimeos\MShop\Common\Manager\Decorator\Address( $this->object, $this->context );
28 | $this->object->setObject( $this->object );
29 | }
30 |
31 |
32 | protected function tearDown() : void
33 | {
34 | unset( $this->object, $this->item, $this->context );
35 | }
36 |
37 |
38 | public function testAggregate()
39 | {
40 | $search = $this->object->filter();
41 | $result = $this->object->aggregate( $search, 'customer.salutation' );
42 |
43 | $this->assertEquals( 2, count( $result ) );
44 | $this->assertArrayHasKey( 'mr', $result );
45 | $this->assertEquals( 1, $result->get( 'mr' ) );
46 | }
47 |
48 |
49 | public function testAggregateMultiple()
50 | {
51 | $cols = ['customer.salutation', 'customer.title'];
52 | $search = $this->object->filter()->order( $cols );
53 | $result = $this->object->aggregate( $search, $cols );
54 |
55 | $this->assertEquals( ['mr' => ['Dr' => 1], '' => ['' => 2]], $result->toArray() );
56 | }
57 |
58 |
59 | public function testGetSearchAttributes()
60 | {
61 | foreach( $this->object->getSearchAttributes() as $attribute )
62 | {
63 | $this->assertInstanceOf( '\\Aimeos\\Base\\Criteria\\Attribute\\Iface', $attribute );
64 | }
65 | }
66 |
67 |
68 | public function testCreateItem()
69 | {
70 | $item = $this->object->create();
71 | $this->assertInstanceOf( '\\Aimeos\\MShop\\Customer\\Item\\Iface', $item );
72 | }
73 |
74 |
75 | public function testGetItem()
76 | {
77 | $domains = ['text', 'customer/property' => ['newsletter']];
78 | $expected = $this->object->find( 'test@example.com', $domains );
79 | $actual = $this->object->get( $expected->getId(), $domains );
80 |
81 | $this->assertEquals( $expected, $actual );
82 | $this->assertEquals( 1, count( $actual->getListItems( 'text' ) ) );
83 | $this->assertEquals( 1, count( $actual->getRefItems( 'text' ) ) );
84 | $this->assertEquals( 1, count( $actual->getPropertyItems() ) );
85 | }
86 |
87 |
88 | public function testSaveUpdateDeleteItem()
89 | {
90 | $search = $this->object->filter();
91 | $search->setConditions( $search->compare( '==', 'customer.code', 'test@example.com' ) );
92 |
93 | if( ( $item = $this->object->search( $search )->first() ) === null ) {
94 | throw new \RuntimeException( 'No customer found.' );
95 | }
96 |
97 | $item->setId( null );
98 | $item->setCode( 'unitTest' );
99 | $item->setLabel( 'unitTest' );
100 | $item->setGroups( array( 1, 2, 3 ) );
101 | $item = $this->object->save( $item );
102 | $itemSaved = $this->object->get( $item->getId() );
103 |
104 | $itemExp = clone $itemSaved;
105 | $itemExp->setCode( 'unitTest2' );
106 | $itemExp->setLabel( 'unitTest2' );
107 | $itemExp->setGroups( array( 2, 4 ) );
108 | $itemExp = $this->object->save( $itemExp );
109 | $itemUpd = $this->object->get( $itemExp->getId() );
110 |
111 | $this->object->delete( $item->getId() );
112 |
113 |
114 | $this->assertInstanceOf( \Aimeos\MShop\Common\Item\Iface::class, $item );
115 | $this->assertInstanceOf( \Aimeos\MShop\Common\Item\Iface::class, $itemExp );
116 |
117 | $this->assertTrue( $item->getId() !== null );
118 | $this->assertEquals( $item->getId(), $itemSaved->getId() );
119 | $this->assertEquals( $item->getSiteId(), $itemSaved->getSiteId() );
120 | $this->assertEquals( $item->getStatus(), $itemSaved->getStatus() );
121 | $this->assertEquals( $item->getCode(), $itemSaved->getCode() );
122 | $this->assertEquals( $item->getLabel(), $itemSaved->getLabel() );
123 | $this->assertEquals( $item->getPassword(), $itemSaved->getPassword() );
124 | $this->assertEquals( $item->getGroups(), $itemSaved->getGroups() );
125 |
126 | $this->assertEquals( 'ai-typo3', $itemSaved->editor() );
127 | $this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemSaved->getTimeCreated() );
128 | $this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemSaved->getTimeModified() );
129 |
130 | $this->assertEquals( $itemExp->getId(), $itemUpd->getId() );
131 | $this->assertEquals( $itemExp->getSiteId(), $itemUpd->getSiteId() );
132 | $this->assertEquals( $itemExp->getStatus(), $itemUpd->getStatus() );
133 | $this->assertEquals( $itemExp->getCode(), $itemUpd->getCode() );
134 | $this->assertEquals( $itemExp->getLabel(), $itemUpd->getLabel() );
135 | $this->assertEquals( $itemExp->getPassword(), $itemUpd->getPassword() );
136 | $this->assertEquals( $itemExp->getGroups(), $itemUpd->getGroups() );
137 |
138 | $this->assertEquals( 'ai-typo3', $itemUpd->editor() );
139 | $this->assertEquals( $itemExp->getTimeCreated(), $itemUpd->getTimeCreated() );
140 | $this->assertMatchesRegularExpression( '/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', $itemUpd->getTimeModified() );
141 |
142 |
143 | $this->expectException( '\\Aimeos\\MShop\\Exception' );
144 | $this->object->get( $item->getId() );
145 | }
146 |
147 |
148 | public function testGetSaveAddressItems()
149 | {
150 | $item = $this->object->find( 'test@example.com', ['customer/address'] );
151 |
152 | $item->setId( null )->setCode( 'xyz' );
153 | $item->getPaymentAddress()->setEmail( 'unittest@xyz.com' );
154 | $item->addAddressItem( new \Aimeos\MShop\Customer\Item\Address\Standard( 'customer.address.' ) );
155 | $this->object->save( $item );
156 |
157 | $item2 = $this->object->find( 'xyz', ['customer/address'] );
158 |
159 | $this->object->delete( $item->getId() );
160 |
161 | $this->assertEquals( 2, count( $item->getAddressItems() ) );
162 | $this->assertEquals( 2, count( $item2->getAddressItems() ) );
163 | }
164 |
165 |
166 | public function testGetSavePropertyItems()
167 | {
168 | $item = $this->object->find( 'test@example.com', ['customer/property'] );
169 |
170 | $item->setId( null )->setCode( 'xyz' );
171 | $item->getPaymentAddress()->setEmail( 'unittest@xyz.com' );
172 | $this->object->save( $item );
173 |
174 | $item2 = $this->object->find( 'xyz', ['customer/property'] );
175 |
176 | $this->object->delete( $item->getId() );
177 |
178 | $this->assertEquals( 1, count( $item->getPropertyItems() ) );
179 | $this->assertEquals( 1, count( $item2->getPropertyItems() ) );
180 | }
181 |
182 |
183 | public function testCreateSearch()
184 | {
185 | $this->assertInstanceOf( '\\Aimeos\\Base\\Criteria\\Iface', $this->object->filter() );
186 | }
187 |
188 |
189 | public function testSearchItems()
190 | {
191 | $item = $this->object->find( 'test@example.com', ['text'] );
192 | $listItem = $item->getListItems( 'text', 'default' )->first( new \RuntimeException( 'No list item found' ) );
193 |
194 | $search = $this->object->filter();
195 |
196 | $expr = [];
197 | $expr[] = $search->compare( '!=', 'customer.id', null );
198 | $expr[] = $search->compare( '==', 'customer.label', 'unitCustomer001' );
199 | $expr[] = $search->compare( '==', 'customer.code', 'test@example.com' );
200 | $expr[] = $search->compare( '>=', 'customer.password', '' );
201 | $expr[] = $search->compare( '==', 'customer.status', 1 );
202 | $expr[] = $search->compare( '>', 'customer.mtime', '1970-01-01 00:00:00' );
203 | $expr[] = $search->compare( '>', 'customer.ctime', '1970-01-01 00:00:00' );
204 | $expr[] = $search->compare( '==', 'customer.editor', $this->context->editor() );
205 |
206 | $expr[] = $search->compare( '==', 'customer.salutation', 'mr' );
207 | $expr[] = $search->compare( '==', 'customer.company', 'Example company' );
208 | $expr[] = $search->compare( '==', 'customer.vatid', 'DE999999999' );
209 | $expr[] = $search->compare( '==', 'customer.title', 'Dr' );
210 | $expr[] = $search->compare( '==', 'customer.firstname', 'Our' );
211 | $expr[] = $search->compare( '==', 'customer.lastname', 'Unittest' );
212 | $expr[] = $search->compare( '=~', 'customer.address1', 'Pickhuben' );
213 | $expr[] = $search->compare( '==', 'customer.postal', '20457' );
214 | $expr[] = $search->compare( '==', 'customer.city', 'Hamburg' );
215 | $expr[] = $search->compare( '==', 'customer.state', 'Hamburg' );
216 | $expr[] = $search->compare( '==', 'customer.languageid', 'de' );
217 | $expr[] = $search->compare( '==', 'customer.countryid', 'DE' );
218 | $expr[] = $search->compare( '==', 'customer.telephone', '055544332211' );
219 | $expr[] = $search->compare( '==', 'customer.email', 'test@example.com' );
220 | $expr[] = $search->compare( '==', 'customer.telefax', '055544332212' );
221 | $expr[] = $search->compare( '==', 'customer.website', 'www.example.com' );
222 | $expr[] = $search->compare( '==', 'customer.longitude', '10.0' );
223 | $expr[] = $search->compare( '==', 'customer.latitude', '50.0' );
224 | $expr[] = $search->compare( '==', 'customer.birthday', '1999-01-01' );
225 |
226 | $param = ['text', 'default', $listItem->getRefId()];
227 | $expr[] = $search->compare( '!=', $search->make( 'customer:has', $param ), null );
228 |
229 | $param = ['text', 'default'];
230 | $expr[] = $search->compare( '!=', $search->make( 'customer:has', $param ), null );
231 |
232 | $param = ['text'];
233 | $expr[] = $search->compare( '!=', $search->make( 'customer:has', $param ), null );
234 |
235 | $param = ['newsletter', null, '1'];
236 | $expr[] = $search->compare( '!=', $search->make( 'customer:prop', $param ), null );
237 |
238 | $param = ['newsletter', null];
239 | $expr[] = $search->compare( '!=', $search->make( 'customer:prop', $param ), null );
240 |
241 | $param = ['newsletter'];
242 | $expr[] = $search->compare( '!=', $search->make( 'customer:prop', $param ), null );
243 |
244 | $expr[] = $search->compare( '!=', 'customer.address.id', null );
245 | $expr[] = $search->compare( '!=', 'customer.address.parentid', null );
246 | $expr[] = $search->compare( '==', 'customer.address.type', 'delivery' );
247 | $expr[] = $search->compare( '==', 'customer.address.salutation', 'mr' );
248 | $expr[] = $search->compare( '==', 'customer.address.company', 'Example company' );
249 | $expr[] = $search->compare( '==', 'customer.address.vatid', 'DE999999999' );
250 | $expr[] = $search->compare( '==', 'customer.address.title', 'Dr' );
251 | $expr[] = $search->compare( '==', 'customer.address.firstname', 'Our' );
252 | $expr[] = $search->compare( '==', 'customer.address.lastname', 'Unittest' );
253 | $expr[] = $search->compare( '==', 'customer.address.address1', 'Pickhuben' );
254 | $expr[] = $search->compare( '==', 'customer.address.address2', '2-4' );
255 | $expr[] = $search->compare( '==', 'customer.address.address3', '' );
256 | $expr[] = $search->compare( '==', 'customer.address.postal', '20457' );
257 | $expr[] = $search->compare( '==', 'customer.address.city', 'Hamburg' );
258 | $expr[] = $search->compare( '==', 'customer.address.state', 'Hamburg' );
259 | $expr[] = $search->compare( '==', 'customer.address.languageid', 'de' );
260 | $expr[] = $search->compare( '==', 'customer.address.countryid', 'DE' );
261 | $expr[] = $search->compare( '==', 'customer.address.telephone', '055544332211' );
262 | $expr[] = $search->compare( '==', 'customer.address.email', 'test@example.com' );
263 | $expr[] = $search->compare( '==', 'customer.address.telefax', '055544332212' );
264 | $expr[] = $search->compare( '==', 'customer.address.website', 'www.example.com' );
265 | $expr[] = $search->compare( '==', 'customer.address.longitude', '10.0' );
266 | $expr[] = $search->compare( '==', 'customer.address.latitude', '50.0' );
267 | $expr[] = $search->compare( '==', 'customer.address.position', 0 );
268 | $expr[] = $search->compare( '>=', 'customer.address.mtime', '1970-01-01 00:00:00' );
269 | $expr[] = $search->compare( '>=', 'customer.address.ctime', '1970-01-01 00:00:00' );
270 | $expr[] = $search->compare( '==', 'customer.address.editor', $this->context->editor() );
271 | $expr[] = $search->compare( '==', 'customer.address.birthday', '2000-01-01' );
272 |
273 | $search->setConditions( $search->and( $expr ) );
274 | $result = $this->object->search( $search );
275 |
276 | $this->assertEquals( 1, count( $result ) );
277 | $this->assertEquals( 1, count( $result->first()->getGroups() ) );
278 | }
279 |
280 |
281 | public function testSearchItemsTotal()
282 | {
283 | $search = $this->object->filter();
284 | $search->slice( 0, 2 );
285 |
286 | $total = 0;
287 | $results = $this->object->search( $search, [], $total );
288 |
289 | $this->assertEquals( 2, count( $results ) );
290 | $this->assertEquals( 3, $total );
291 | }
292 |
293 |
294 | public function testSearchItemsCriteria()
295 | {
296 | $search = $this->object->filter( true );
297 | $results = $this->object->search( $search );
298 |
299 | $this->assertEquals( 2, count( $results ) );
300 |
301 | foreach( $results as $itemId => $item ) {
302 | $this->assertEquals( $itemId, $item->getId() );
303 | }
304 | }
305 |
306 |
307 | public function testSearchItemsRef()
308 | {
309 | $search = $this->object->filter();
310 | $search->setConditions( $search->compare( '==', 'customer.code', 'test@example.com' ) );
311 |
312 | if( ( $item = $this->object->search( $search, ['customer/address', 'text'] ) ) === null ) {
313 | throw new \Exception( 'No customer item for "test@example.com" available' );
314 | }
315 |
316 | $this->assertEquals( 1, count( $item->getRefItems( 'text' ) ) );
317 | $this->assertEquals( 1, count( $item->getAddressItems() ) );
318 | }
319 |
320 |
321 | public function testGetSubManager()
322 | {
323 | $this->expectException( \LogicException::class );
324 | $this->object->getSubManager( 'unknown' );
325 | }
326 |
327 |
328 | public function testGetSubManagerInvalidName()
329 | {
330 | $this->expectException( \LogicException::class );
331 | $this->object->getSubManager( 'address', 'unknown' );
332 | }
333 | }
334 |
--------------------------------------------------------------------------------
/src/MShop/Group/Manager/Typo3.php:
--------------------------------------------------------------------------------
1 | array(
25 | 'code' => 'group.id',
26 | 'internalcode' => 'mgro."uid"',
27 | 'label' => 'Group ID',
28 | 'type' => 'int',
29 | ),
30 | 'group.code' => array(
31 | 'code' => 'group.code',
32 | 'internalcode' => 'mgro."title"',
33 | 'label' => 'Group code',
34 | 'type' => 'string',
35 | ),
36 | 'group.label' => array(
37 | 'code' => 'group.label',
38 | 'internalcode' => 'mgro."description"',
39 | 'label' => 'Group label',
40 | 'type' => 'string',
41 | ),
42 | 'group.ctime'=> array(
43 | 'code' => 'group.ctime',
44 | 'internalcode' => 'mgro."crdate"',
45 | 'label' => 'Group creation time',
46 | 'type' => 'datetime',
47 | ),
48 | 'group.mtime'=> array(
49 | 'code' => 'group.mtime',
50 | 'internalcode' => 'mgro."tstamp"',
51 | 'label' => 'Group modification time',
52 | 'type' => 'datetime',
53 | ),
54 | 'group.editor'=> array(
55 | 'code' => 'group.editor',
56 | 'internalcode' => '',
57 | 'label' => 'Group editor',
58 | 'type' => 'string',
59 | ),
60 | );
61 |
62 | private array $plugins = [];
63 | private array $reverse = [];
64 | private int $pid;
65 |
66 |
67 | /**
68 | * Initializes the group manager object
69 | *
70 | * @param \Aimeos\MShop\ContextIface $context Context object with required objects
71 | */
72 | public function __construct( \Aimeos\MShop\ContextIface $context )
73 | {
74 | parent::__construct( $context );
75 |
76 | $plugin = new \Aimeos\Base\Criteria\Plugin\T3Datetime();
77 | $this->plugins['ctime'] = $this->reverse['crdate'] = $plugin;
78 | $this->plugins['mtime'] = $this->reverse['tstamp'] = $plugin;
79 |
80 | /** mshop/group/manager/typo3/pid-default
81 | * Page ID the group records are assigned to
82 | *
83 | * In TYPO3, you can assign fe_group records to different sysfolders based
84 | * on their page ID. These sysfolders can be use for user authorization and
85 | * therefore, you need to assign the correct page ID to groups
86 | * created or modified by the Aimeos admin backend.
87 | *
88 | * @param int TYPO3 page ID
89 | * @since 2018.10
90 | * @see mshop/customer/manager/typo3/pid-default
91 | */
92 | $this->pid = (int) $context->config()->get( 'mshop/customer/manager/typo3/pid-default', 0 );
93 | $this->pid = (int) $context->config()->get( 'mshop/group/manager/typo3/pid-default', $this->pid );
94 | }
95 |
96 |
97 | /**
98 | * Removes old entries from the database
99 | *
100 | * @param integer[] $siteids List of IDs for sites whose entries should be deleted
101 | * @return \Aimeos\MShop\Common\Manager\Iface Same object for fluent interface
102 | */
103 | public function clear( iterable $siteids ) : \Aimeos\MShop\Common\Manager\Iface
104 | {
105 | $path = 'mshop/group/manager/submanagers';
106 |
107 | foreach( $this->context()->config()->get( $path, [] ) as $domain ) {
108 | $this->object()->getSubManager( $domain )->clear( $siteids );
109 | }
110 |
111 | return $this;
112 | }
113 |
114 |
115 | /**
116 | * Removes multiple items.
117 | *
118 | * @param \Aimeos\MShop\Common\Item\Iface[]|string[] $itemIds List of item objects or IDs of the items
119 | * @return \Aimeos\MShop\Common\Manager\Iface Manager object for chaining method calls
120 | */
121 | public function delete( $itemIds ) : \Aimeos\MShop\Common\Manager\Iface
122 | {
123 | /** mshop/group/manager/typo3/delete/mysql
124 | * Deletes the items matched by the given IDs from the database
125 | *
126 | * @see mshop/group/manager/typo3/delete/ansi
127 | */
128 |
129 | /** mshop/group/manager/typo3/delete/ansi
130 | * Deletes the items matched by the given IDs from the database
131 | *
132 | * Removes the records specified by the given IDs from the group
133 | * database. The records must be from the site that is configured via the
134 | * context item.
135 | *
136 | * The ":cond" placeholder is replaced by the name of the ID column and
137 | * the given ID or list of IDs while the site ID is bound to the question
138 | * mark.
139 | *
140 | * The SQL statement should conform to the ANSI standard to be
141 | * compatible with most relational database systems. This also
142 | * includes using double quotes for table and column names.
143 | *
144 | * @param string SQL statement for deleting items
145 | * @since 2015.08
146 | * @category Developer
147 | * @see mshop/group/manager/typo3/insert/ansi
148 | * @see mshop/group/manager/typo3/update/ansi
149 | * @see mshop/group/manager/typo3/newid/ansi
150 | * @see mshop/group/manager/typo3/search/ansi
151 | * @see mshop/group/manager/typo3/count/ansi
152 | */
153 | $path = 'mshop/group/manager/typo3/delete';
154 |
155 | return $this->deleteItemsBase( $itemIds, $path, false, 'uid' );
156 | }
157 |
158 |
159 | /**
160 | * Returns the additional column/search definitions
161 | *
162 | * @return array Associative list of column names as keys and items implementing \Aimeos\Base\Criteria\Attribute\Iface
163 | */
164 | public function getSaveAttributes() : array
165 | {
166 | return [];
167 | }
168 |
169 |
170 | /**
171 | * Returns the attributes that can be used for searching
172 | *
173 | * @param bool $withsub Return attributes of sub-managers too if true
174 | * @return array List of attribute items implementing \Aimeos\Base\Criteria\Attribute\Iface
175 | */
176 | public function getSearchAttributes( bool $withsub = true ) : array
177 | {
178 | $path = 'mshop/group/manager/submanagers';
179 |
180 | return $this->getSearchAttributesBase( $this->searchConfig, $path, [], $withsub );
181 | }
182 |
183 |
184 | /**
185 | * Returns a new manager for group extensions
186 | *
187 | * @param string $manager Name of the sub manager type in lower case
188 | * @param string|null $name Name of the implementation, will be from configuration (or Default) if null
189 | * @return \Aimeos\MShop\Common\Manager\Iface Manager for different extensions
190 | */
191 | public function getSubManager( string $manager, ?string $name = null ) : \Aimeos\MShop\Common\Manager\Iface
192 | {
193 | return $this->getSubManagerBase( 'group/group', $manager, ( $name === null ? 'Typo3' : $name ) );
194 | }
195 |
196 |
197 | /**
198 | * Inserts a new or updates an existing group item
199 | *
200 | * @param \Aimeos\MShop\Group\Item\Iface $item Group item
201 | * @param boolean $fetch True if the new ID should be returned in the item
202 | * @return \Aimeos\MShop\Group\Item\Iface $item Updated item including the generated ID
203 | */
204 | protected function saveItem( \Aimeos\MShop\Group\Item\Iface $item, bool $fetch = true ) : \Aimeos\MShop\Group\Item\Iface
205 | {
206 | if( !$item->isModified() ) {
207 | return $item;
208 | }
209 |
210 | $context = $this->context();
211 | $conn = $context->db( $this->getResourceName() );
212 | $time = date_create_from_format( 'Y-m-d H:i:s', $context->datetime() )->getTimestamp();
213 |
214 | $id = $item->getId();
215 | $columns = $this->object()->getSaveAttributes();
216 |
217 | if( $id === null )
218 | {
219 | /** mshop/group/manager/typo3/insert/mysql
220 | * Inserts a new group record into the database table
221 | *
222 | * @see mshop/group/manager/typo3/insert/ansi
223 | */
224 |
225 | /** mshop/group/manager/typo3/insert/ansi
226 | * Inserts a new group record into the database table
227 | *
228 | * Items with no ID yet (i.e. the ID is NULL) will be created in
229 | * the database and the newly created ID retrieved afterwards
230 | * using the "newid" SQL statement.
231 | *
232 | * The SQL statement must be a string suitable for being used as
233 | * prepared statement. It must include question marks for binding
234 | * the values from the group item to the statement before
235 | * they are sent to the database server. The number of question
236 | * marks must be the same as the number of columns listed in the
237 | * INSERT statement. The order of the columns must correspond to
238 | * the order in the save() method, so the correct values are
239 | * bound to the columns.
240 | *
241 | * The SQL statement should conform to the ANSI standard to be
242 | * compatible with most relational database systems. This also
243 | * includes using double quotes for table and column names.
244 | *
245 | * @param string SQL statement for inserting records
246 | * @since 2015.08
247 | * @category Developer
248 | * @see mshop/group/manager/typo3/update/ansi
249 | * @see mshop/group/manager/typo3/newid/ansi
250 | * @see mshop/group/manager/typo3/delete/ansi
251 | * @see mshop/group/manager/typo3/search/ansi
252 | * @see mshop/group/manager/typo3/count/ansi
253 | */
254 | $path = 'mshop/group/manager/typo3/insert';
255 | $sql = $this->addSqlColumns( array_keys( $columns ), $this->getSqlConfig( $path ) );
256 | }
257 | else
258 | {
259 | /** mshop/group/manager/typo3/update/mysql
260 | * Updates an existing group record in the database
261 | *
262 | * @see mshop/group/manager/typo3/update/ansi
263 | */
264 |
265 | /** mshop/group/manager/typo3/update/ansi
266 | * Updates an existing group record in the database
267 | *
268 | * Items which already have an ID (i.e. the ID is not NULL) will
269 | * be updated in the database.
270 | *
271 | * The SQL statement must be a string suitable for being used as
272 | * prepared statement. It must include question marks for binding
273 | * the values from the group item to the statement before
274 | * they are sent to the database server. The order of the columns
275 | * must correspond to the order in the save() method, so the
276 | * correct values are bound to the columns.
277 | *
278 | * The SQL statement should conform to the ANSI standard to be
279 | * compatible with most relational database systems. This also
280 | * includes using double quotes for table and column names.
281 | *
282 | * @param string SQL statement for updating records
283 | * @since 2015.08
284 | * @category Developer
285 | * @see mshop/group/manager/typo3/insert/ansi
286 | * @see mshop/group/manager/typo3/newid/ansi
287 | * @see mshop/group/manager/typo3/delete/ansi
288 | * @see mshop/group/manager/typo3/search/ansi
289 | * @see mshop/group/manager/typo3/count/ansi
290 | */
291 | $path = 'mshop/group/manager/typo3/update';
292 | $sql = $this->addSqlColumns( array_keys( $columns ), $this->getSqlConfig( $path ), false );
293 | }
294 |
295 | $idx = 1;
296 | $stmt = $this->getCachedStatement( $conn, $path, $sql );
297 |
298 | foreach( $columns as $name => $entry ) {
299 | $stmt->bind( $idx++, $item->get( $name ), \Aimeos\Base\Criteria\SQL::type( $entry->getType() ) );
300 | }
301 |
302 | $stmt->bind( $idx++, $this->pid, \Aimeos\Base\DB\Statement\Base::PARAM_INT );
303 | $stmt->bind( $idx++, $item->getCode() );
304 | $stmt->bind( $idx++, $item->getLabel() );
305 | $stmt->bind( $idx++, $time, \Aimeos\Base\DB\Statement\Base::PARAM_INT ); // mtime
306 |
307 | if( $id !== null ) {
308 | $stmt->bind( $idx++, $id, \Aimeos\Base\DB\Statement\Base::PARAM_INT );
309 | $item->setId( $id );
310 | } else {
311 | $stmt->bind( $idx++, $time, \Aimeos\Base\DB\Statement\Base::PARAM_INT ); // ctime
312 | }
313 |
314 | $stmt->execute()->finish();
315 |
316 | if( $id === null && $fetch === true )
317 | {
318 | /** mshop/group/manager/typo3/newid/mysql
319 | * Retrieves the ID generated by the database when inserting a new record
320 | *
321 | * @see mshop/group/manager/typo3/newid/ansi
322 | */
323 |
324 | /** mshop/group/manager/typo3/newid/ansi
325 | * Retrieves the ID generated by the database when inserting a new record
326 | *
327 | * As soon as a new record is inserted into the database table,
328 | * the database server generates a new and unique identifier for
329 | * that record. This ID can be used for retrieving, updating and
330 | * deleting that specific record from the table again.
331 | *
332 | * For MySQL:
333 | * SELECT LAST_INSERT_ID()
334 | * For PostgreSQL:
335 | * SELECT currval('seq_mcus_id')
336 | * For SQL Server:
337 | * SELECT SCOPE_IDENTITY()
338 | * For Oracle:
339 | * SELECT "seq_mcus_id".CURRVAL FROM DUAL
340 | *
341 | * There's no way to retrive the new ID by a SQL statements that
342 | * fits for most database servers as they implement their own
343 | * specific way.
344 | *
345 | * @param string SQL statement for retrieving the last inserted record ID
346 | * @since 2015.08
347 | * @category Developer
348 | * @see mshop/group/manager/typo3/insert/ansi
349 | * @see mshop/group/manager/typo3/update/ansi
350 | * @see mshop/group/manager/typo3/delete/ansi
351 | * @see mshop/group/manager/typo3/search/ansi
352 | * @see mshop/group/manager/typo3/count/ansi
353 | */
354 | $path = 'mshop/group/manager/typo3/newid';
355 | $item->setId( $this->newId( $conn, $path ) );
356 | }
357 |
358 | return $item;
359 | }
360 |
361 |
362 | /**
363 | * Returns the item objects matched by the given search criteria.
364 | *
365 | * @param \Aimeos\Base\Criteria\Iface $search Search criteria object
366 | * @param array $ref List of domain items that should be fetched too
367 | * @param int|null &$total Number of items that are available in total
368 | * @return \Aimeos\Map List of items implementing \Aimeos\MShop\Group\Item\Iface
369 | * @throws \Aimeos\MShop\Exception If retrieving items failed
370 | */
371 | public function search( \Aimeos\Base\Criteria\Iface $search, array $ref = [], ?int &$total = null ) : \Aimeos\Map
372 | {
373 | $map = [];
374 | $context = $this->context();
375 | $conn = $context->db( $this->getResourceName() );
376 |
377 | $required = array( 'group' );
378 | $level = \Aimeos\MShop\Locale\Manager\Base::SITE_ALL;
379 |
380 | /** mshop/group/manager/typo3/search
381 | * Retrieves the records matched by the given criteria in the database
382 | *
383 | * Fetches the records matched by the given criteria from the group
384 | * database. The records must be from one of the sites that are
385 | * configured via the context item. If the current site is part of
386 | * a tree of sites, the SELECT statement can retrieve all records
387 | * from the current site and the complete sub-tree of sites.
388 | *
389 | * As the records can normally be limited by criteria from sub-managers,
390 | * their tables must be joined in the SQL context. This is done by
391 | * using the "internaldeps" property from the definition of the ID
392 | * column of the sub-managers. These internal dependencies specify
393 | * the JOIN between the tables and the used columns for joining. The
394 | * ":joins" placeholder is then replaced by the JOIN strings from
395 | * the sub-managers.
396 | *
397 | * To limit the records matched, conditions can be added to the given
398 | * criteria object. It can contain comparisons like column names that
399 | * must match specific values which can be combined by AND, OR or NOT
400 | * operators. The resulting string of SQL conditions replaces the
401 | * ":cond" placeholder before the statement is sent to the database
402 | * server.
403 | *
404 | * If the records that are retrieved should be ordered by one or more
405 | * columns, the generated string of column / sort direction pairs
406 | * replaces the ":order" placeholder. In case no ordering is required,
407 | * the complete ORDER BY part including the "\/*-orderby*\/...\/*orderby-*\/"
408 | * markers is removed to speed up retrieving the records. Columns of
409 | * sub-managers can also be used for ordering the result set but then
410 | * no index can be used.
411 | *
412 | * The number of returned records can be limited and can start at any
413 | * number between the begining and the end of the result set. For that
414 | * the ":size" and ":start" placeholders are replaced by the
415 | * corresponding values from the criteria object. The default values
416 | * are 0 for the start and 100 for the size value.
417 | *
418 | * The SQL statement should conform to the ANSI standard to be
419 | * compatible with most relational database systems. This also
420 | * includes using double quotes for table and column names.
421 | *
422 | * @param string SQL statement for searching items
423 | * @since 2015.08
424 | * @category Developer
425 | * @see mshop/group/manager/typo3/count
426 | */
427 | $cfgPathSearch = 'mshop/group/manager/typo3/search';
428 |
429 | /** mshop/group/manager/typo3/count
430 | * Counts the number of records matched by the given criteria in the database
431 | *
432 | * Counts all records matched by the given criteria from the group
433 | * database. The records must be from one of the sites that are
434 | * configured via the context item. If the current site is part of
435 | * a tree of sites, the statement can count all records from the
436 | * current site and the complete sub-tree of sites.
437 | *
438 | * As the records can normally be limited by criteria from sub-managers,
439 | * their tables must be joined in the SQL context. This is done by
440 | * using the "internaldeps" property from the definition of the ID
441 | * column of the sub-managers. These internal dependencies specify
442 | * the JOIN between the tables and the used columns for joining. The
443 | * ":joins" placeholder is then replaced by the JOIN strings from
444 | * the sub-managers.
445 | *
446 | * To limit the records matched, conditions can be added to the given
447 | * criteria object. It can contain comparisons like column names that
448 | * must match specific values which can be combined by AND, OR or NOT
449 | * operators. The resulting string of SQL conditions replaces the
450 | * ":cond" placeholder before the statement is sent to the database
451 | * server.
452 | *
453 | * Both, the strings for ":joins" and for ":cond" are the same as for
454 | * the "search" SQL statement.
455 | *
456 | * Contrary to the "search" statement, it doesn't return any records
457 | * but instead the number of records that have been found. As counting
458 | * thousands of records can be a long running task, the maximum number
459 | * of counted records is limited for performance reasons.
460 | *
461 | * The SQL statement should conform to the ANSI standard to be
462 | * compatible with most relational database systems. This also
463 | * includes using double quotes for table and column names.
464 | *
465 | * @param string SQL statement for counting items
466 | * @since 2015.08
467 | * @category Developer
468 | * @see mshop/group/manager/typo3/search
469 | */
470 | $cfgPathCount = 'mshop/group/manager/typo3/count';
471 |
472 | $results = $this->searchItemsBase( $conn, $search, $cfgPathSearch, $cfgPathCount, $required, $total, $level );
473 |
474 | while( $row = $results->fetch() ) {
475 | $map[(string) $row['group.id']] = $this->createItemBase( $row );
476 | }
477 |
478 | return map( $map );
479 | }
480 |
481 |
482 | /**
483 | * Creates a new group item.
484 | *
485 | * @param array $values List of attributes for group item
486 | * @return \Aimeos\MShop\Group\Item\Iface New group item
487 | */
488 | protected function createItemBase( array $values = [] ) : \Aimeos\MShop\Group\Item\Iface
489 | {
490 | $values['group.siteid'] = $this->context()->locale()->getSiteId();
491 |
492 | if( array_key_exists( 'group.mtime', $values ) ) {
493 | $values['group.mtime'] = $this->reverse['tstamp']->reverse( $values['group.mtime'] );
494 | }
495 |
496 | if( array_key_exists( 'group.ctime', $values ) ) {
497 | $values['group.ctime'] = $this->reverse['crdate']->reverse( $values['group.ctime'] );
498 | }
499 |
500 | return new \Aimeos\MShop\Group\Item\Standard( 'group.', $values );
501 | }
502 | }
503 |
--------------------------------------------------------------------------------