conversion of magento 1 into magento 2 - magento2

I was using fetch_assoc() method in magento 1 .
I want to convert it into Magento 2 . there is no fetch_assoc() method in magento 2.
if(is_object($result))
{
while ($resultsArray =$result->fetch_assoc())
{
if(empty($data))
{
$data[] = array_keys($resultsArray);
}
$data[] = $resultsArray;
} var_dump($data);
}

I'm not sure my proposed solution is useful for you or not but the best approach to fetch data in Magento 2 is based on Models and Collections.
Step 1: Firstly, you have to create a Model file in your module
<?php
namespace <Vendor_Name>\<Module_Name>\Model;
use Magento\Framework\Model\AbstractModel;
class Data extends AbstractModel
{
protected function _construct()
{
$this->_init('<Vendor_Name>\<Module_Name>\Model\ResourceModel\Data');
}
}
Step 2: Create ResourceModel file in your custom module
<?php
namespace <Vendor_Name>\<Module_Name>\Model\ResourceModel;
use \Magento\Framework\Model\ResourceModel\Db\AbstractDb;
class Data extends AbstractDb
{
protected function _construct()
{
// Second parameter is a primary key of the table
$this->_init('Table_Name', 'id');
}
}
Step 3: Create Collection file to initialize Model and ResourceModel files.
namespace <Vendor_Name>\<Module_Name>\Model\ResourceModel\Data;
use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;
class Collection extends AbstractCollection
{
protected function _construct()
{
$this->_init(
'<Vendor_Name>\<Module_Name>\Model\Data',
'<Vendor_Name>\<Module_Name>\Model\ResourceModel\Data'
);
}
}
Step 4: Last thing that you need to do is create a Block file in the same module and utilize collection, something like this:
namespace <Vendor_Name>\<Module_Name>\Block;
use Magento\Framework\View\Element\Template\Context;
use Magento\Framework\View\Element\Template;
use <Vendor_Name>\<Module_Name>\Model\Data as DataCollection;
class Custom_Module extends Template
{
protected $dataCollection;
public function __construct(Context $context, DataCollection $dataCollection)
{
$this->_dataCollection = $dataCollection;
parent::__construct($context);
}
public function getDataCollecton()
{
$collection = $this->_dataCollection->getCollection();
return $collection;
}
}
Another Solution
You can also use fetchAll instead of fetch_assoc() in Magento 2, if you don't want to implement models and collections based solution, something like this:
// Select Data from table
$sql = "Select * FROM " . $tableName;
$result = $connection->fetchAll($sql);
and for reference, you can also have a look into Magento2 – Write Custom Mysql Query (Without Using Model)

I think we can use something like below :
$adapter = $this->resourceConnection->getConnection($resource);
$stmt = $adapter->query($sql);
// Use FETCH_NUM so we are not dependent on the CASE attribute of the PDO connection
$results = $stmt->fetchAll(\Zend_Db::FETCH_ASSOC);
Or if we have $connection instanceof \Magento\Framework\DB\Adapter\AdapterInterface
$connection->fetchAll($sql, $binds, \PDO::FETCH_ASSOC);
By using those, i think you're gonna get the same result to magento 1 fetch_assoc

Alternative of the fetch_assoc() in magento 2 is fetchAssoc($SQL_QUERY)
Below is the example.
For get order where status is pending data using fetchAssoc(SQL_QUERY)
<?php
namespace Path\To\Class;
use Magento\Framework\App\ResourceConnection;
class fetchAssoc {
const ORDER_TABLE = 'sales_order';
/**
* #var ResourceConnection
*/
private $resourceConnection;
public function __construct(
ResourceConnection $resourceConnection
) {
$this->resourceConnection = $resourceConnection;
}
/**
* fetchAssoc Sql Query
*
* #return string[]
*/
public function fetchAssocQuery()
{
$connection = $this->resourceConnection->getConnection();
$tableName = $connection->getTableName(self::ORDER_TABLE);
$query = $connection->select()
->from($tableName,['entity_id','status','grand_total'])
->where('status = ?', 'pending');
$fetchData = $connection->fetchAssoc($query);
return $fetchData;
}
}

In magento 2 you can use same but for that you need to create database connection.
I suggest you to use resource or collection models to get the result and if you want to get the first row in object format then you should use
getFirstItem();

I think Magento 2 has support for this in class \Magento\Framework\DB\Adapter\AdapterInterface. You can create an instance for AdapterInterface by dependency injection or directly by object manager.
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
/** #var \Magento\Framework\App\ResourceConnection $resourceConnection */
$resourceConnection = $objectManager->get(\Magento\Framework\App\ResourceConnection::class);
/** #var \Magento\Framework\DB\Adapter\AdapterInterface $connection */
$connection = $resourceConnection->getConnection(\Magento\Framework\App\ResourceConnection::DEFAULT_CONNECTION);
$sql = "YOUR SELECT QUERY HERE";
$data = $connection->fetchAssoc($sql);

Related

TYPO3 FileReference repository query search through file name

I have made a 'document' model which contains a field 'file' which is a FileReference. Now im working on a repository query function that retrieves all documents containing certain string in the files name ( using $query->like() for this ). However I run against the following error:
When ever I disable this $query->like and I debug the 'document' that I receive it looks like the relation information regarding the field 'uidLocal' is correct because I receive the name of the file.
Some more code im using:
class FileReference extends \TYPO3\CMS\Extbase\Domain\Model\FileReference
{
/**
* #var \**\***\Domain\Model\File
*/
protected $uidLocal;
/**
* #param \**\***\Domain\Model\File $uidLocal
* #return void
*/
public function setUidLocal($uidLocal)
{
$this->uidLocal = $uidLocal;
}
/**
* #return \**\***\Domain\Model\File
*/
public function getUidLocal()
{
return $this->uidLocal;
}
}
The repository query:
$query->matching(
$query->logicalAnd(
$query->greaterThanOrEqual('crdate', $from),
$query->contains('usergroups', $participant),
// TODO: Onderstaande check moet aan maar resulteerd in error..
$query->like('file.uidLocal.name', '%'.$filename.'_'.$type.'.%')
)
);
Now I can ofcourse filter the document name after the query but that wont do well for the performance of the task. Does anyone know what im missing and where the error comes from?
Thanks in advance for contributing ideas,
Falko
I guess you are trying something like that?
$query = $this->createQuery();
$query->matching($query->like('file.uidLocal.name', '%somefile%'));
I am not sure if you can join from sys_file_reference to sys_file with extbase query.
For me it looks like the TCA or the FileReference Model is not implemented that way.
Maybe a workaround is to create a custom sql query wich returns uids and then create your document models with something like ->findAllByUids($uids);
Here is a working example wich uses the query builder instead of extbase query.
class ArticleRepository extends Repository
{
public function findAllByFilename($filename)
{
/* #var $queryBuilder \TYPO3\CMS\Core\Database\Query\QueryBuilder */
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable('tx_example_domain_model_article');
$queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
$res = $queryBuilder
->select('article.uid')
->from('tx_example_domain_model_article', 'article')
->leftJoin('article', 'sys_file_reference', 'reference',
$queryBuilder->expr()->andX(
$queryBuilder->expr()->eq('reference.uid_foreign', $queryBuilder->quoteIdentifier('article.uid')),
$queryBuilder->expr()->eq('reference.tablenames', $queryBuilder->quote('tx_example_domain_model_article')),
$queryBuilder->expr()->eq('reference.fieldname', $queryBuilder->quote('image')),
$queryBuilder->expr()->eq('reference.table_local', $queryBuilder->quote('sys_file'))
))
->leftJoin('article', 'sys_file', 'file',
$queryBuilder->expr()->eq('file.uid', $queryBuilder->quoteIdentifier('reference.uid_local'))
)
->where($queryBuilder->expr()->eq('file.name', $queryBuilder->createNamedParameter($filename)))
->execute();
debug($queryBuilder->getSQL());
$uids = [];
while ($row = $res->fetch()) {
$uids[] = $row['uid'];
}
return $this->findAllByUids($uids);
}
public function findAllByUids($uids) {
$query = $this->createQuery();
$query->matching($query->in('uid', $uids));
return $query->execute();
}

TYPO3 Extbase: How to get disabled related Object, without raw sql-query?

Scenario:
I have following model:
ContactPerson has a relation to FrontendUser and is the owning side of the relation. Now I have following problem:
I am activating/deactivating the FrontendUsers in a task, based on the ContactPersons which are active. When the FrontendUser is disabled or deleted the result of contactPerson->getFrontendUser() is null, even if both repositories ignoreEnableFields:
/** #var Typo3QuerySettings $querySettings */
$querySettings = $this->objectManager->get(Typo3QuerySettings::class);
$querySettings->setIgnoreEnableFields(true);
$querySettings->setRespectStoragePage(false);
$this->frontendUserRepository->setDefaultQuerySettings($querySettings);
$debugContactPerson = $this->contactPersonRepository->findOneByContactPersonIdAndIncludeDeletedAndHidden('634');
$debugFrontendUser = $this->frontendUserRepository->findOneByUid(7);
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump(
array(
'$debugContactPerson' => $debugContactPerson,
'$debugFrontendUser' => $debugFrontendUser,
)
);
Result:
P.s.: $this->frontendUserRepository->findByUid(7); also doesn't work because it isn't using the query, but persistenceManager->getObjectByIdentifier(... which is of course ignoring the query-settings.
The problem is, in my real code I can't use findOneByUid(), because I can't get the integer-Value(uid) in the frontend_user field of the contact_person.
Any way to solve this without using a raw query to get the contact_person-row?
My (yes raw query) Solution:
Because I didn't want to write an own QueryFactory and I didn't want to add a redundant field to my contactPerson I solved it now with a raw statement. Maybe it can help someone with the same problem:
class FrontendUserRepository extends \TYPO3\CMS\Extbase\Domain\Repository\FrontendUserRepository
{
/**
* #param \Vendor\ExtKey\Domain\Model\ContactPerson $contactPerson
* #return Object
*/
public function findByContactPersonByRawQuery(ContactPerson $contactPerson){
$query = $this->createQuery();
$query->statement(
"SELECT fe_users.* FROM fe_users" .
" LEFT JOIN tx_extkey_domain_model_contactperson contact_person ON contact_person.frontend_user = fe_users.uid" .
" WHERE contact_person.uid = " . $contactPerson->getUid()
);
return $query->execute()->getFirst();
}
}
Invoking repository directly
There are two aspects for the enable fields of table fe_users:
$querySettings->setIgnoreEnableFields(true);
$querySettings->setEnableFieldsToBeIgnored(['disable']);
Have a look to some overview in the wiki page - it says 6.2, but it's still valid in most parts for 7.6 and 8 as well. However, this only works if the repository is invoked directly, but not if an entity is retrieved as part of another entity - in this case the repository is not used for nested entities.
Modify query settings for nested entities
Nested entities are retrieved implicitly - this happens in DataMapper::getPreparedQuery(DomainObjectInterface $parentObject, $propertyName). To adjust query settings for child entities, the QueryFactoryInterface implementation has to be overloaded.
Register an alternative implementation in ext_localconf.php (replace \Vendor\ExtensionName\Persistence\Generic\QueryFactory with the real class name of your extension):
$extbaseObjectContainer = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
\TYPO3\CMS\Extbase\Object\Container\Container::class
);
$extbaseObjectContainer->registerImplementation(
\TYPO3\CMS\Extbase\Persistence\Generic\QueryFactoryInterface::class,
\Vendor\ExtensionName\Persistence\Generic\QueryFactory::class
);
With new Typo3 versions (v8+), the registerImplementation method no longer works for QueryFactory. Instead, a XCLASS must be used to overwrite/extend the class:
$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][\TYPO3\CMS\Extbase\Persistence\Generic\QueryFactory::class] = [
'className' => \Vendor\ExtensionName\Persistence\Generic\QueryFactory::class,
];
Then inside the implementation:
<?php
namespace \Vendor\ExtensionName\Persistence\Generic;
use TYPO3\CMS\Extbase\Domain\Model\FrontendUser;
class QueryFactory extends \TYPO3\CMS\Extbase\Persistence\Generic\QueryFactory {
public function create($className) {
$query = parent::create($className);
if (is_a($className, FrontendUser::class, true)) {
// #todo Find a way to configure that more generic
$querySettings = $query->getQuerySettings();
$querySettings->setIgnoreEnableFields(true);
// ... whatever you need to adjust in addition ...
}
return $query;
}
}
My solution of this problem was to disable the "enablecolumns" in TCA definitions and deal this in the repository myself.
Here an example of findAll method:
public function findAll($ignoreEnableFields = false) {
$query = $this->createQuery();
if (!$ignoreEnableFields) {
$currTime = time();
$query->matching(
$query->logicalAnd(
$query->equals("hidden", 0),
$query->logicalOr(
$query->equals("starttime", 0),
$query->lessThanOrEqual("starttime", $currTime)
),
$query->logicalOr(
$query->equals("endtime", 0),
$query->greaterThanOrEqual("endtime", $currTime)
)
)
);
}
return $query->execute();
}

How to get current category in magento2?

How can i get current category in magento2 ?
I want to get category name and category id in custom phtml file.
The above to seem correct, but I think that jumping straight to the Registry is not the best approach. Magento provides a Layer Resolver that already encapsulates that functionality. (See the TopMenu Block in the Catalog Plugins)
I suggest injecting the \Magento\Catalog\Model\Layer\Resolver class and using that to get the current category. Here is the code :
<?php
namespace FooBar\Demo\Block;
class Demo extends \Magento\Framework\View\Element\Template
{
private $layerResolver;
public function __construct(
\Magento\Framework\View\Element\Template\Context $context,
\Magento\Catalog\Model\Layer\Resolver $layerResolver,
array $data = []
) {
parent::__construct($context, $data);
$this->layerResolver = $layerResolver;
}
public function getCurrentCategory()
{
return $this->layerResolver->get()->getCurrentCategory();
}
}
Here is what the actual getCurrentCategory() method does in the Resolver Class.
public function getCurrentCategory()
{
$category = $this->getData('current_category');
if ($category === null) {
$category = $this->registry->registry('current_category');
if ($category) {
$this->setData('current_category', $category);
} else {
$category = $this->categoryRepository->get($this->getCurrentStore()->getRootCategoryId());
$this->setData('current_category', $category);
}
}
return $category;
}
As you can see, it does still use the registry but it provides a fallback in case that fails.
Magento sets registry for categories being accessed. So, to get currenct category, use following method:
/**
* #param \Magento\Framework\Registry $registry
*/
protected $_registry;
public function __construct(
\Magento\Framework\Registry $registry
) {
$this->_registry = $registry;
}
and then use:
$category = $this->_registry->registry('current_category');//get current category
Now you can access the collection and fetch details such as $category->getName()
No need to use the object manager or inject class. You can use a built-in helper class Magento\Catalog\Helper\Data in the following way.
<?php
$catalogHelperData = $this->helper('Magento\Catalog\Helper\Data');
$categoryObject = $catalogHelperData->getCategory();
$categoryId = $categoryObject->getId();
$categoryName = $categoryObject->getName();
?>
This code snippet should work for any phtml (built-in or custom) file which is related to product listing page or product detail page.
Try this code. this will definitely help you.
<?php
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$category = $objectManager->get('Magento\Framework\Registry')->registry('current_category');//get current category
echo $category->getId();
echo $category->getName();
?>
In *.phtml files at Category page can get Category data with following snippet:
$currentCategory = $this->helper('Magento\Catalog\Helper\Data')->getCategory();

Zend duplicated rows on mysql insert

For some reason, when I do an mysql db insert from Zend, my row is dulpicated. I've tried a direct insert via phpmyadmin and it works perfect, so its not a mysql server problem.
This is the code I use:
<?php
class Model_Team extends Zend_Db_Table_Abstract {
protected $_name = 'team';
public function createUser($data) {
$user = $this->createRow();
$user->name = $data['name'];
$user->title = $data['title'];
$id = $user->save();
return $id;
}
}
?>
Thanks in advance.
EDIT:
I've found that this duplication only occurs when i call the form via AJAX (modal box), although the form post is normal, not an ajax request)
I don't know why your code is double pumping the database on save but it should'nt matter as you're using the Row object and save(). (save() inserts or updates)
You may want to restructure your createUser() function so that it can't create a new row if the row already exists.
<?php
class Model_Team extends Zend_Db_Table_Abstract {
protected $_name = 'team';
public function createUser(array $data) {
$user = $this->createRow();
//test if user has id in the array
if (array_key_exists('id', $data)){
$user->id = $data['id'];
}
$user->name = $data['name'];
$user->title = $data['title'];
$user->save();
//no need to create a new variable to return the user row
return $user;
}
}
This method will create and update a user row.
To help you further I'll need to see the controller code most of my double pumps have happened there.
Instead of using createRow() have you tried using insert()?
/**
* Insert array of data as new row into database
* #param array $data associative array of column => value pairs.
* #return int Primary Key of inserted row
*/
public function createUser($data)
{
return $this->insert($data);
}
Also - could we see the ajax code? It may be that the form is being posted as well?

Using Image Content Objects from tt_content in Extbase

I want to write an Extbase Backend module which needs a list of all Objects generated from tt_content with CType = 'image'.
Now I started defining a simple model
class Tx_Myextension_Domain_Model_Content extends Tx_Extbase_DomainObject_AbstractEntity
{
/**
* #var string
*/
protected $header;
/**
* #return the $header
*/
public function getHeader()
{
return $this->header;
}
/**
* #param string $header
*/
public function setHeader($header)
{
$this->header = $header;
}
}
and a Repository
class Tx_Myextension_Domain_Repository_ContentRepository extends Tx_Extbase_Persistence_Repository
{
public function initializeObject()
{
$querySettings = $this->objectManager->create('Tx_Extbase_Persistence_Typo3QuerySettings');
$querySettings->setRespectStoragePage(FALSE);
$this->setDefaultQuerySettings($querySettings);
}
}
As far as I know the initializeObject method is a way to get all content elements, no matter which pid they have.
At last I tried to map my Content Class on tt_content:
plugin.tx_myextension {
persistence {
classes {
Tx_Myextension_Domain_Model_Content {
mapping {
tableName = tt_content
recordType = Tx_Myextension_Domain_Model_Content
columns {
header.mapOnProperty = header
}
}
}
}
}
}
module.tx_myextension {
persistence < plugin.tx_myextension.persistence
}
No I want to use the Repo. e.g. countAll. Unfortunately it always returns 0. Looking for the MySQL query discovers the problem:
SELECT COUNT(*)
FROM tt_content
WHERE (tt_content.CType='Tx_Myextension_Domain_Model_Content')
AND tt_content.deleted=0 AND tt_content.hidden=0
AND (tt_content.starttime<=1313073660)
AND (tt_content.endtime=0 OR tt_content.endtime>1313073660)
AND tt_content.sys_language_uid IN (0,-1)
AND tt_content.pid IN (0)
Typo 3 or Extbase or something different added all these where clauses to the query. I just want to get rid of the CType and pid clauses. As I said, I thought that the method used in the Repo leads to ignoring the pid, which is obviously not the case.
Can somebody help me? All I want is an array of Image Content Elements. Thank you in advance.
Late answer: You'll most likely want to call
query->getQuerySettings()
->setRespectEnableFields(FALSE)
->setRespectSysLanguage(FALSE);
for your query. You can disable it for all queries in your repository's initializeObject method:
$querySettings = $this->objectManager->create('Tx_Extbase_Persistence_Typo3QuerySettings');
$querySettings
->setRespectStoragePage(FALSE)
->setRespectEnableFields(FALSE)
->setRespectSysLanguage(FALSE);
$this->setDefaultQuerySettings($querySettings);
See: TYPO 3 API docs
Try to remove the Node "recordType" from your Persistence Definition.