I have very specific problem with my Zend Framework application. I use my own Model class called My_Model which is singleton and I use it for calling DB models. Every model extends My_Db_Table class and has a row class that extends My_Db_Table_Row. When I call the model it is OK but the model seems to ignore row class model. Could anybody advise me what am I doing wrong?
The custom class:
class My_Model {
protected static $_instance = null;
protected $_services = array();
private function __construct() {
}
/**
* Service classed is called by it's name
*
* #param string $name
* #return My_Db_Table
*/
public function getService($name) {
if (!isset($this->_services[$name])) {
$service = new $name();
if (!$service instanceof Zend_Db_Table_Abstract) {
$type = gettype($service);
if ($type == 'object') {
$type = get_class($service);
}
throw new Zend_Db_Table_Row_Exception("Class must be a Zend_Db_Table_Abstract, but it is $type");
}
$this->_services[$name] = $service;
}
return $this->_services[$name];
}
}
The Zend_Db_Table classes are:
<?php
/**
* This class represents a DB table
*
*/
class My_Db_Table extends Zend_Db_Table_Abstract {
/**
* Fetches the table row by primary key
*
* #param string $id
* #return Product
*/
public function getById($id) {
return $this->find($id)->current();
}
}
Row class:
<?php
/**
* Row class
*
*/
class My_Db_Table_Row extends Zend_Db_Table_Row_Abstract {
/**
* Inflector to get the attribute name
* camelCase -> under_score
*
* #param string $columnName
* #return string
*/
protected function _transformColumn($columnName) {
$inflector = new Zend_Filter_Inflector ( ":string" );
$inflector->setRules ( array (
':string' => array ('Word_CamelCaseToUnderscore', 'StringToLower' ) ) )
;
$columnName = $inflector->filter ( array ('string' => $columnName ) );
return $columnName;
}
/**
* Magic method hook to catch getters and setters
*
* #param string $method
* #param array $args
*/
public function __call($method, array $args) {
$matches = array ();
if (preg_match ( '/^get(\w+?)$/', $method, $matches )) {
$attribute = $matches [1];
return $this->{$attribute};
}
if (preg_match ( '/^set(\w+?)$/', $method, $matches )) {
$attribute = $matches [1];
$this->{$attribute} = (count ( $args ) == 1) ? $args [0] : null;
return;
}
return parent::__call ( $method, $args );
}
}
To use these classe I use following code:
$record = My_Model::getInstance ()->getService ( 'Users' )->getById ( 1 );
$record->updateFromArray(array('auth_token' => 'asfsgfgswg'));
And I get the following error message:
Message: Unrecognized method 'updateFromArray()'
Stack trace:
#0 /home/www/fbdrives/application/modules/facebook/controllers/IndexController.php(34): Zend_Db_Table_Row_Abstract->__call('updateFromArray', Array)
#1 /home/www/fbdrives/application/modules/facebook/controllers/IndexController.php(34): Zend_Db_Table_Row->updateFromArray(Array)
#2 /home/www/fbdrives/library/Zend/Controller/Action.php(513): Facebook_IndexController->indexAction()
#3 /home/www/fbdrives/library/Zend/Controller/Dispatcher/Standard.php(295): Zend_Controller_Action->dispatch('indexAction')
#4 /home/www/fbdrives/library/Zend/Controller/Front.php(954): Zend_Controller_Dispatcher_Standard->dispatch(Object(Zend_Controller_Request_Http), Object(Zend_Controller_Response_Http))
#5 /home/www/fbdrives/library/Zend/Application/Bootstrap/Bootstrap.php(97): Zend_Controller_Front->dispatch()
#6 /home/www/fbdrives/library/Zend/Application.php(366): Zend_Application_Bootstrap_Bootstrap->run()
#7 /home/www/fbdrives/public/index.php(27): Zend_Application->run()
#8 {main}
The Users class:
<?php
/**
* User table model class
*
*/
class Users extends My_Db_Table {
/**
* The DB table name
*
* #var string
*/
protected $_name = 'user';
/**
* The row class name
*
* #var string
*/
protected $_rowclass = 'User';
}
The User class that is not called with updateFromArray method:
<?php
/**
* The user model class
*
*/
class User extends My_Db_Table_Row {
/**
* Update values by array values
*
* #param array $values
*/
public function updateFromArray(array $values) {
$this->setFromArray($values);
$this->save();
return $this;
}
}
I will provide any necessary info if needed. I am really stucked on this one for a few days now and nothing seems to help. The method updateFromArray is in the User class but the class is not loaded properly.
Thanks in advance for every help!
I think the problem may be that you are using $_rowclass and not $_rowClass (with an uppercase C).
If you put this line instead, it may work:
protected $_rowClass = 'User';
That's why in the stack trace you can see Zend_Db_Table being called, which is the default class for a a row that hasn't been set to use a custom class.
Related
I'm trying to get the value from Index controller.
Controller\Adminhtml\Orders\Index.php :
public function execute()
{
$storeid = $this->getRequest()->getParam('storeid');
$this->settings->setStoreid($storeid);
}
Model\Settings.php
public function setStoreid($storeid)
{
$this->storeid = $storeid;
}
public function getStoreid()
{
return $this->storeid;
}
Model\ResourceModel\Order\Grid\Collection.php :
public function _renderFiltersBefore{
$storeid = $this->getStoreId();
// var_dump($storeid)
// $storeid = 5
$this->getSelect()->where('store_id = ?', $storeid);
}
I want to pass the storeid to the query Collection. I can able to set the storeid from Index class and can able to get the storeid in Collection class. But it doesnt passing to the collection.
If I set the value directly to storeid, ie. $storeid = 5, then collection works fine. Please advice.
Maybe try to use registry
/**
* #var \Magento\Framework\Registry
*/
protected $_registry;
/**
* ...
* ...
* #param \Magento\Framework\Registry $registry,
*/
public function __construct(
...,
...,
\Magento\Framework\Registry $registry,
...
) {
$this->_registry = $registry;
...
...
}
/**
* Setting custom variable in registry to be used
*
*/
public function setCustomVariable()
{
$this->registry->register('custom_var', 'Added Value');
}
/**
* Retrieving custom variable from registry
* #return string
*/
public function getCustomVariable()
{
return $this->registry->registry('custom_var');
}
I'm creating a content Element with gridelments where i need to render some Data from the childs directly. There is no problem for fields like "bodytext" or "header". But the assets gives me only a counter, not a reference or path.
So the big question: How can i render the assets images from the childs?
I can share a VH I just did
<?php
namespace GeorgRinger\Theme\ViewHelpers;
use TYPO3\CMS\Core\Database\DatabaseConnection;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper;
use TYPO3\CMS\Frontend\Resource\FileCollector;
class FalViewHelper extends AbstractViewHelper
{
/**
* #var boolean
*/
protected $escapeOutput = FALSE;
/**
* #param string $table
* #param string $field
* #param string $id
* #param string $as
* #return string
*/
public function render($table, $field, $id, $as = 'references')
{
$row = $this->getDatabaseConnection()->exec_SELECTgetSingleRow('*', $table, 'uid=' . (int)$id);
if (!$row) {
return '';
}
$fileCollector = GeneralUtility::makeInstance(FileCollector::class);
$fileCollector->addFilesFromRelation($table, $field, $row);
$this->templateVariableContainer->add($as, $fileCollector->getFiles());
$output = $this->renderChildren();
$this->templateVariableContainer->remove($as);
return $output;
}
/**
* #return DatabaseConnection
*/
protected function getDatabaseConnection()
{
return $GLOBALS['TYPO3_DB'];
}
}
Of course you need to adopt the namspace.
Usage would be
<theme:fal table="tt_content" field="assets" id=" => the id <= ">
<f:debug>{references}</f:debug>
</theme:fal>
I am trying to develop a custom extension using TYPO3 extbase repository method. I want to fetch tt_content "pi_flexform" field value in my extension.
For achieving this I've followed persistence method.
In typoscript configuration files I've added like this;
plugin.tx_myext{
persistence {
classes {
\TYPO3\MyExt\Domain\Model\Myext {
mapping {
tableName = tt_content
recordType = \TYPO3\MyExt\Domain\Model\Myext
columns {
pi_flexform.mapOnProperty = piflexform
}
}
}
}
}
}
In my model file I've implemented the following code;
/**
* #var string
*/
protected $piflexform;
/**
* #return the $piflexform
*/
public function getPiflexform()
{
return $this->piflexform;
}
/**
* #param string $piflexform
*/
public function setPiflexform($piflexform)
{
$this->piflexform = $piflexform;
}
And also in the repository file;
$queryStmt = "SELECT pi_flexform FROM tt_content WHERE CType = 'dce_dce10' AND pid = 1 AND sys_language_uid = 0";
$query = $this->createQuery();
$query->statement( $queryStmt );
return $query->execute();
But it returns an empty object.
TYPO3\CMS\Extbase\Persistence\Generic\QueryResultprototypeobject (empty)
0 => TYPO3\VstRssfeed\Domain\Model\Vstrssfeedprototypepersistent entity (uid=0, pid=0)
piflexform => NULL
uid => 0 (integer)
_localizedUid => 0 (integer)modified
_languageUid => 0 (integer)modified
_versionedUid => 0 (integer)modified
pid => 0 (integer)
Can you guys please help me to solve this problem? Thanks in advance.
How to Effectively use the Repository and Query Object of Extbase?
http://blog.typoplanet.de/2010/01/27/the-repository-and-query-object-of-extbase/
Here's an example how your repository should look like:
myext/Classes/Domain/Repository/ContentRepository.php
<?php
namespace TYPO3\MyExt\Domain\Repository;
/**
* Class ContentRepository
* #package TYPO3\MyExt\Domain\Repository
*/
class ContentRepository extends \TYPO3\CMS\Extbase\Persistence\Repository {
/**
* Initializes the repository.
*
* #return void
*/
public function initializeObject() {
/** #var $querySettings \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings */
$querySettings = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Typo3QuerySettings');
$querySettings->setRespectStoragePage(FALSE);
$this->setDefaultQuerySettings($querySettings);
}
/**
* Find By CType
*
* #param string $cType
* #param integer $pid
* #return \TYPO3\CMS\Extbase\Persistence\QueryResultInterface
*/
public function findByCtype($cType, $pid = FALSE) {
$constraints = array();
$query = $this->createQuery();
$constraints[] = $query->equals('CType', $cType);
if ($pid) {
$constraints[] = $query->equals('pid', $pid);
}
if ($constraints) {
if (count($constraints) == 1) {
$query->matching($constraints[0]);
} else {
$query->matching($query->logicalAnd($constraints));
}
}
return $query->execute();
}
}
And here's an example how your controller should do the work:
myext/Classes/Controller/SomeController.php
class SomeController extends \TYPO3\CMS\E... {
/**
* #var \TYPO3\MyExt\Domain\Repository\ContentRepository
* #inject
*/
protected $contentRepository = NULL;
public function someAction() {
$contents = $this->contentRepository->findByCtype('dce_dce10');
if ($contents) {
foreach ($contents as $content) {
echo '<h1>'.$content->getUid().'</h1>';
echo PHP_EOL.'<br />';
echo $content->getPiflexform();
echo PHP_EOL.'<br />';
}
}
}
}
I'm new to Doctrine ODM and i'm totally stuck with a simple query :(
Let me start with the document structure:
Array
(
[_id] => 4ee1e4527f749c9411000012
[voteList] => Array
(
[_id] => 4ee1e4527f749c9411000013
[votes] => Array
(
... stripped ...
)
[latest] => Array
(
[_id] => 4ee1e4527f749c9411000014
[rating] => 1
[voter] => Array
(
[$ref] => Voter
[$id] => 4ee1e4527f749c941100000f
[$db] => x_test
)
)
)
... stripped ...
)
This document is called Voting.
My Question is, how to find Voting-documents by a particular voter (which is stored in voteList.latest.voter).
I tried it like this:
$builder
->field('voteList.latest.voter')->references($voter)
->getQuery()
->execute();
And this way also:
$result = $builder
->field('voteList.latest.voter.$id')->equals(new \MongoId($voter->getId()))
->getQuery()
->execute();
Both are leading to this exception:
Doctrine\ODM\MongoDB\MongoDBException: No mapping found for field 'voteList.latest.voter' in class 'App\BaseBundle\Document\Voting'.
Am i building the query incorrectly or might something be wrong with my document classes?
Thanks for reading, any advices appreciated.
EDIT: Documents attached
/**
* #ODM\Document(repositoryClass="App\BaseBundle\Document\VotingRepository")
*/
class Voting
{
/**
* #ODM\Id
* #var int
*/
protected $id;
/**
* #ODM\EmbedOne(targetDocument="App\BaseBundle\Document\VoteList")
* #var VoteList
*/
protected $voteList;
public function __construct()
{
if ($this->voteList === null) {
$this->voteList = new VoteList();
}
}
/**
* #return string
*/
public function getId()
{
return $this->id;
}
/**
* #return VoteList
*/
public function getVoteList()
{
return $this->voteList;
}
}
;
/**
* #ODM\EmbeddedDocument
*/
class VoteList implements \Countable, \ArrayAccess, \IteratorAggregate
{
/**
* #ODM\Id
*/
protected $id;
/**
* #ODM\EmbedMany(targetDocument="App\BaseBundle\Document\Vote")
* #var Vote[]
*/
protected $votes = array();
/**
* #ODM\EmbedOne(targetDocument="App\BaseBundle\Document\Vote")
* #var Vote
*/
protected $latest;
public function getId()
{
return $this->id;
}
/**
* #return Vote
*/
public function getLatest()
{
return $this->latest;
}
}
/**
* #ODM\EmbeddedDocument
*/
class Vote
{
/**
* #ODM\Id
*/
protected $id;
/**
* #ODM\ReferenceOne(targetDocument="App\BaseBundle\Document\Voter")
* #var Voter
*/
public $voter;
public function getId()
{
return $this->id;
}
public function getVoter()
{
return $this->voter;
}
public function setVoter(Voter $voter)
{
$this->voter = $voter;
}
}
Figured out it's not working due to a doctrine-odm bug.
https://github.com/doctrine/mongodb-odm/pull/207
Simple one hopefully, is there a specific way i should be updating a single database value using a model in Zend Framework.
I currently do this:
class Model_MyModel extends Zend_Db_Table_Abstract
{
$_name = 'table';
public function updateSetting($id,$status)
{
$data = array(
'status' => $status
);
$this->update($data, 'id = '.$id);
}
}
$update = new Model_MyModel();
$update->updateSetting(10,1);
Obviously i could pass in another argument as the column to update. I just wondered if there was a more "magic" way i should be doing this?
You could write a simple property overloader for this:
class Model_MyModel extends Zend_Db_Table_Abstract
{
protected $_name = 'table';
/**
* Should be a Zend_Db_Table_Row instance
*
* #var Zend_Db_Table_Row
*/
protected $_currentRow = null;
/**
* Property overloader
*
* For more information on this see
* http://www.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.members
*
* #param string $key
* #param string $value
* #return void
*/
public function __set($key, $value)
{
$row = $this->getCurrentRow();
if (null !== $row)
{
$row->$key = $value;
}
else
{
throw new Exception('Cannot update a column on a non existent row!');
}
}
/**
* Save current row
*
* #return Model_MyModel
*/
public function saveCurrentRow()
{
$row = $this->getCurrentRow();
if (null !== $row)
{
$row->save();
}
else
{
throw new Exception('Cannot save a non existent row!');
}
}
/**
* Set current row
*
* #param Zend_Db_Table_Row $row
* #return Model_MyModel
*/
public function setCurrentRow(Zend_Db_Table_Row $row)
{
$this->_currentRow = $row;
return $this;
}
/**
* Get current row
*
* #return Zend_Db_Table_Row
*/
public function getCurrentRow()
{
return $this->_currentRow;
}
}
You could then do stuff like this:
$model = new Model_MyModel();
$model->status = 'foo';
$model->somecolumn = 'bar'
$model->saveCurrentRow();
Although this approach would require the least editing in your code, an even better approach would be seperating your models from your database tables and use a Data Mapper Pattern as described in the Quickstart.