Question

I'm trying to figure out how shipment tracking data is stored. Especially when it's set by the API. So when I look at sales/etc/webapi.xml I see the following.

<route url="/V1/shipment/track" method="POST">
    <service class="Magento\Sales\Api\ShipmentTrackRepositoryInterface" method="save"/>
    <resources>
        <resource ref="Magento_Sales::sales" />
    </resources>
</route>

This leads me to sales/etc/di.xml where I see the following:

<preference for="Magento\Sales\Api\ShipmentTrackRepositoryInterface" 
            type="Magento\Sales\Api\Data\ShipmentTrack\Repository"/>

Now this is where my question starts. Because I can't seem to find a class named Magento\Sales\Api\Data\ShipmentTrack\Repository. Or am I missing something here?

Was it helpful?

Solution

You can find the Magento 2 generation logic here, especialy for repositories :

If the class is missing, Magento will try to generate it

For your case here : {magento-root-dir}/var/generation/Magento/Sales/Api/Data/Shi‌​pmentTrack.php

vendor/magento/magento2-base/app/etc/di.xml

<type name="Magento\Framework\Code\Generator">
    <arguments>
        <argument name="generatedEntities" xsi:type="array">
            <item name="factory" xsi:type="string">\Magento\Framework\ObjectManager\Code\Generator\Factory</item>
            <item name="proxy" xsi:type="string">\Magento\Framework\ObjectManager\Code\Generator\Proxy</item>
            <item name="interceptor" xsi:type="string">\Magento\Framework\Interception\Code\Generator\Interceptor</item>
            <item name="logger" xsi:type="string">\Magento\Framework\ObjectManager\Profiler\Code\Generator\Logger</item>
            <item name="mapper" xsi:type="string">\Magento\Framework\Api\Code\Generator\Mapper</item>
            <item name="persistor" xsi:type="string">\Magento\Framework\ObjectManager\Code\Generator\Persistor</item>
            <item name="repository" xsi:type="string">\Magento\Framework\ObjectManager\Code\Generator\Repository</item>
            <item name="convertor" xsi:type="string">\Magento\Framework\ObjectManager\Code\Generator\Converter</item>
            <item name="searchResults" xsi:type="string">\Magento\Framework\Api\Code\Generator\SearchResults</item>
            <item name="extensionInterface" xsi:type="string">\Magento\Framework\Api\Code\Generator\ExtensionAttributesInterfaceGenerator</item>
            <item name="extension" xsi:type="string">\Magento\Framework\Api\Code\Generator\ExtensionAttributesGenerator</item>
        </argument>
    </arguments>
</type>

vendor/magento/framework/ObjectManager/Code/Generator/Repository.php

<?php
/**
 * Copyright © 2016 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */

// @codingStandardsIgnoreFile

namespace Magento\Framework\ObjectManager\Code\Generator;

/**
 * Class Repository
 */
class Repository extends \Magento\Framework\Code\Generator\EntityAbstract
{
    /**
     * Entity type
     */
    const ENTITY_TYPE = 'repository';

    /**
     * No Such Entity Exception
     */
    const NO_SUCH_ENTITY_EXCEPTION = '\\Magento\Framework\Exception\NoSuchEntityException';
    const INPUT_EXCEPTION = '\\Magento\Framework\Exception\InputException';
    const SEARCH_CRITERIA = '\\Magento\Framework\Api\SearchCriteria';

    /**
     * Retrieve class properties
     *
     * @return array
     */
    protected function _getClassProperties()
    {
        $properties = [
            [
                'name' => $this->_getSourcePersistorPropertyName(),
                'visibility' => 'protected',
                'docblock' => [
                    'shortDescription' => $this->_getSourcePersistorPropertyName(),
                    'tags' => [
                        [
                            'name' => 'var',
                            'description' => $this->_getPersistorClassName(),
                        ],
                    ],
                ],
            ],
            [
                'name' => $this->_getSourceCollectionFactoryPropertyName(),
                'visibility' => 'protected',
                'docblock' => [
                    'shortDescription' => 'Collection Factory',
                    'tags' => [
                        [
                            'name' => 'var',
                            'description' => $this->_getCollectionFactoryClassName(),
                        ],
                    ],
                ]
            ],
            [
                'name' => 'registry',
                'visibility' => 'protected',
                'defaultValue' => [],
                'docblock' => [
                    'shortDescription' => $this->getSourceClassName() . '[]',
                    'tags' => [
                        [
                            'name' => 'var',
                            'description' => 'array',
                        ],
                    ],
                ]
            ],
            [
                'name' => 'extensionAttributesJoinProcessor',
                'visibility' => 'protected',
                'docblock' => [
                    'shortDescription' => 'Extension attributes join processor.',
                    'tags' => [
                        [
                            'name' => 'var',
                            'description' => '\Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface',
                        ],
                    ],
                ]
            ],
        ];
        return $properties;
    }

    /**
     * Returns source factory property name
     *
     * @return string
     */
    protected function _getSourcePersistorPropertyName()
    {
        return lcfirst($this->getSourceClassNameWithoutNamespace()) . 'Persistor';
    }

    /**
     * Returns source collection factory property name
     * @return string
     */
    protected function _getSourceCollectionFactoryPropertyName()
    {
        return lcfirst($this->getSourceClassNameWithoutNamespace()) . 'SearchResultFactory';
    }

    /**
     * Returns collection factory class name
     *
     * @return string
     */
    protected function _getCollectionFactoryClassName()
    {
        return
            str_replace('Interface', '', $this->getSourceClassName()) . 'SearchResultInterfaceFactory';
    }
    /**
     * Returns source persistor class name
     *
     * @return string
     */
    protected function _getPersistorClassName()
    {
        $target = $this->getSourceClassName();
//        if (substr($target, -9) == 'Interface') {
//            $target = substr($target, 1, strlen($target) -9);
//        }
        return $target . 'Persistor';
    }

    /**
     * Get default constructor definition for generated class
     *
     * @return array
     */
    protected function _getDefaultConstructorDefinition()
    {
        return [
            'name' => '__construct',
            'parameters' => [
                [
                    'name' => $this->_getSourcePersistorPropertyName(),
                    'type' => $this->_getPersistorClassName(),
                ],
                [
                    'name' => $this->_getSourceCollectionFactoryPropertyName(),
                    'type' => $this->_getCollectionFactoryClassName(),
                ],
                [
                    'name' => 'extensionAttributesJoinProcessor',
                    'type' => '\Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface',
                ],
            ],
            'body' => "\$this->"
                . $this->_getSourcePersistorPropertyName()
                . " = \$" . $this->_getSourcePersistorPropertyName() . ";\n"
                . "\$this->"
                . $this->_getSourceCollectionFactoryPropertyName()
                . " = \$" . $this->_getSourceCollectionFactoryPropertyName() . ";\n"
                . "\$this->extensionAttributesJoinProcessor = \$extensionAttributesJoinProcessor;"
            ,
            'docblock' => [
                'shortDescription' => ucfirst(static::ENTITY_TYPE) . ' constructor',
                'tags' => [
                    [
                        'name' => 'param',
                        'description' => $this->getSourceClassName() . " \$" . $this->_getSourcePersistorPropertyName(),
                    ],
                    [
                        'name' => 'param',
                        'description' => $this->_getCollectionFactoryClassName()
                            . " \$" . $this->_getSourceCollectionFactoryPropertyName()
                    ],
                    [
                        'name' => 'param',
                        'description' => '\Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface'
                            . " \$extensionAttributesJoinProcessor"
                    ],
                ],
            ]
        ];
    }

    /**
     * Returns get() method
     *
     * @return string
     */
    protected function _getGetMethod()
    {
        $body = "if (!\$id) {\n"
            . "    throw new " . self::INPUT_EXCEPTION . "('ID required');\n"
            . "}\n"
            . "if (!isset(\$this->registry[\$id])) {\n"
            . "    \$entity = \$this->" . $this->_getSourcePersistorPropertyName()
            . "->loadEntity(\$id);\n"
            . "    if (!\$entity->getId()) {\n"
            . "        throw new " . self::NO_SUCH_ENTITY_EXCEPTION . "('Requested entity doesn\\'t exist');\n"
            . "    }\n"
            . "    \$this->registry[\$id] = \$entity;\n"
            . "}\n"
            . "return \$this->registry[\$id];";
        return [
            'name' => 'get',
            'parameters' => [
                [
                    'name' => 'id',
                    'type' => 'int',
                ],
            ],
            'body' => $body,
            'docblock' => [
                'shortDescription' => 'load entity',
                'tags' => [
                    [
                        'name' => 'param',
                        'description' => 'int $id',
                    ],
                    [
                        'name' => 'return',
                        'description' => $this->getSourceClassName(),
                    ],
                    [
                        'name' => 'throws',
                        'description' => self::INPUT_EXCEPTION,
                    ],
                    [
                        'name' => 'throws',
                        'description' => self::NO_SUCH_ENTITY_EXCEPTION,
                    ],
                ],
            ]
        ];
    }

    /**
     * Returns register() method
     *
     * @return string
     */
    protected function _getCreateFromArrayMethod()
    {
        $body = "return \$this->{$this->_getSourcePersistorPropertyName()}->registerFromArray(\$data);";
        return [
            'name' => 'createFromArray',
            'parameters' => [
                [
                    'name' => 'data',
                    'type' => 'array',
                ],
            ],
            'body' => $body,
            'docblock' => [
                'shortDescription' => 'Register entity to create',
                'tags' => [
                    [
                        'name' => 'param',
                        'description' => 'array $data',
                    ],
                    [
                        'name' => 'return',
                        'description' => $this->_getResultClassName(),
                    ],
                ],
            ]
        ];
    }

    /**
     * Returns register() method
     *
     * @return string
     */
    protected function _getCreateMethod()
    {
        $body = "return \$this->{$this->_getSourcePersistorPropertyName()}->registerNew(\$entity);";
        return [
            'name' => 'create',
            'parameters' => [
                [
                    'name' => 'entity',
                    'type' => $this->getSourceClassName(),
                ],
            ],
            'body' => $body,
            'docblock' => [
                'shortDescription' => 'Register entity to create',
                'tags' => [
                    [
                        'name' => 'param',
                        'description' => 'array $data',
                    ],
                    [
                        'name' => 'return',
                        'description' => $this->getSourceClassName(),
                    ],
                ],
            ]
        ];
    }

    /**
     * Returns register() method
     *
     * @return string
     */
    protected function _getFlushMethod()
    {
        $body = "\$ids = \$this->{$this->_getSourcePersistorPropertyName()}->doPersist();\n"
            . "foreach (\$ids as \$id) {\n"
            . "unset(\$this->registry[\$id]);\n"
            . "}";
        return [
            'name' => 'flush',
            'parameters' => [],
            'body' => $body,
            'docblock' => [
                'shortDescription' => 'Perform persist operations',
                'tags' => [],
            ]
        ];
    }

    /**
     * Returns persist() method
     *
     * @return string
     */
    protected function _getSaveMethod()
    {
        $body = "\$this->{$this->_getSourcePersistorPropertyName()}->doPersistEntity(\$entity);\n"
            . "return \$entity;";
        return [
            'name' => 'save',
            'parameters' => [
                [
                    'name' => 'entity',
                    'type' => $this->getSourceClassName(),
                ],
            ],
            'body' => $body,
            'docblock' => [
                'shortDescription' => 'Perform persist operations for one entity',
                'tags' => [
                    [
                        'name' => 'param',
                        'description' => $this->getSourceClassName() . " \$entity",
                    ],
                    [
                        'name' => 'return',
                        'description' => $this->getSourceClassName(),
                    ],
                ],
            ]
        ];
    }

    /**
     * Return remove() method
     *
     * @return array
     */
    protected function _getDeleteMethod()
    {
        $body = "\$this->{$this->_getSourcePersistorPropertyName()}->registerDeleted(\$entity);\n"
            . "return \$this->{$this->_getSourcePersistorPropertyName()}->doPersistEntity(\$entity);";
        return [
            'name' => 'delete',
            'parameters' => [
                [
                    'name' => 'entity',
                    'type' => $this->getSourceClassName(),
                ],
            ],
            'body' => $body,
            'docblock' => [
                'shortDescription' => 'Register entity to delete',
                'tags' => [
                    [
                        'name' => 'param',
                        'description' => $this->getSourceClassName() . ' $entity',
                    ],
                    [
                        'name' => 'return',
                        'description' => 'bool',
                    ],
                ],
            ]
        ];
    }

    /**
     * Return remove() method
     *
     * @return array
     */
    protected function _getDeleteByIdMethod()
    {
        $body = "\$entity = \$this->get(\$id);\n"
            . "\$this->{$this->_getSourcePersistorPropertyName()}->registerDeleted(\$entity);\n"
            . "return \$this->{$this->_getSourcePersistorPropertyName()}->doPersistEntity(\$entity);";
        return [
            'name' => 'deleteById',
            'parameters' => [
                [
                    'name' => 'id',
                    'type' => 'int',
                ],
            ],
            'body' => $body,
            'docblock' => [
                'shortDescription' => 'Delete entity by Id',
                'tags' => [
                    [
                        'name' => 'param',
                        'description' => 'int $id',
                    ],
                    [
                        'name' => 'return',
                        'description' => 'bool',
                    ],
                ],
            ]
        ];
    }

    /**
     * Return remove() method
     *
     * @return array
     */
    protected function _getRemoveMethod()
    {
        $body = "\$this->{$this->_getSourcePersistorPropertyName()}->registerDeleted(\$entity);";
        return [
            'name' => 'remove',
            'parameters' => [
                [
                    'name' => 'entity',
                    'type' => $this->getSourceClassName(),
                ],
            ],
            'body' => $body,
            'docblock' => [
                'shortDescription' => 'Register entity to delete',
                'tags' => [
                    [
                        'name' => 'param',
                        'description' => $this->getSourceClassName() . ' $entity',
                    ],
                ],
            ]
        ];
    }

    /**
     * Returns getList() method
     *
     * @return string
     */
    protected function _getGetListMethod()
    {
        $body = "\$collection = \$this->" . $this->_getSourceCollectionFactoryPropertyName() . "->create();\n"
        . "\$this->extensionAttributesJoinProcessor->process(\$collection);\n"
        . "foreach (\$searchCriteria->getFilterGroups() as \$filterGroup) {\n"
        . "    foreach (\$filterGroup->getFilters() as \$filter) {\n"
        . "        \$condition = \$filter->getConditionType() ? \$filter->getConditionType() : 'eq';\n"
        . "        \$collection->addFieldToFilter(\$filter->getField(), [\$condition => \$filter->getValue()]);\n"
        . "    }\n"
        . "}\n"
        . "\$collection->setCurPage(\$searchCriteria->getCurrentPage());\n"
        . "\$collection->setPageSize(\$searchCriteria->getPageSize());\n"
        . "return \$collection;\n";
        return [
            'name' => 'getList',
            'parameters' => [
                [
                    'name' => 'searchCriteria',
                    'type' => self::SEARCH_CRITERIA,
                ],
            ],
            'body' => $body,
            'docblock' => [
                'shortDescription' => 'Find entities by criteria',
                'tags' => [
                    [
                        'name' => 'param',
                        'description' => self::SEARCH_CRITERIA . ' $searchCriteria',
                    ],
                    [
                        'name' => 'return',
                        'description' => $this->getSourceClassName() . '[]',
                    ],
                ],
            ]
        ];
    }

    /**
     * Returns list of methods for class generator
     *
     * @return array
     */
    protected function _getClassMethods()
    {
        return [
            $this->_getDefaultConstructorDefinition(),
            $this->_getGetMethod(),
            $this->_getCreateMethod(),
            $this->_getCreateFromArrayMethod(),
            $this->_getGetListMethod(),
            $this->_getRemoveMethod(),
            $this->_getDeleteMethod(),
            $this->_getDeleteByIdMethod(),
            $this->_getFlushMethod(),
            $this->_getSaveMethod()
        ];
    }

    /**
     * {@inheritdoc}
     */
    protected function _validateData()
    {
        $result = parent::_validateData();

        if ($result) {
            $sourceClassName = $this->getSourceClassName();
            $resultClassName = $this->_getResultClassName();

            if ($resultClassName !== str_replace('Interface', '', $sourceClassName) . '\\Repository') {
                $this->_addError(
                    'Invalid Factory class name [' . $resultClassName . ']. Use ' . $sourceClassName . 'Repository'
                );
                $result = false;
            }
        }
        return $result;
    }

    /**
     * Generate code
     *
     * @return string
     */
    protected function _generateCode()
    {
        $className = str_replace('Interface', '', str_replace('Data\\', '', $this->getSourceClassName()));
        $this->_classGenerator->setName(
            $this->_getResultClassName()
        )->addProperties(
            $this->_getClassProperties()
        )->addMethods(
            $this->_getClassMethods()
        )->setClassDocBlock(
            $this->_getClassDocBlock()
        )->setImplementedInterfaces(
            [
                $className . 'RepositoryInterface',
            ]
        );
        return $this->_getGeneratedCode();
    }

    /**
     * Get source class name
     *
     * @return string
     */
    public function getSourceClassName()
    {
        return parent::getSourceClassName() . 'Interface';
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top