Is there a way to add a default scope to a Zend_Db_Table_Abstract based model.
I want to be able to query a model with some conditions taken as default.
e.g.
deleted = false
order name asc
You can override the Zend_Db_Table_Abstract:: _fetch() method and modify the generated Zend_Db_Table_Select in there before retrieving the rows from the database adapter. As far as I know all fetch*-methods and find() in Zend_Db_Table_Abstract boil down to this generic row-retrieval-method (besides Zend_Db_Table_Abstract::fetchNew() naturally), so your modified code will be called everytime rows are retrieved from the database.
/**
* Support method for fetching rows.
*
* #param Zend_Db_Table_Select $select query options.
* #return array An array containing the row results in FETCH_ASSOC mode.
*/
protected function _fetch(Zend_Db_Table_Select $select)
{
$select->where('deleted = false')->order('name asc');
return parent:: _fetch($select);
}
Related
in a extbase extension i us sys_category. In list action there is no problem, all categories work as expected. But i want to write category entries with a custom database finisher from tx_form.
In the model all seems correct:
/**
* Sets the categories
*
* #param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $categories
* #return void
*/
public function setCategories($categories)
{
$this->categories = $categories;
}
in my finisher:
$newAddress->setCategories($newCat);
$this->addressRepository->add($newAddress);
The form gives me only the uid of the category but for "setCategories" i need an \TYPO3\CMS\Extbase\Persistence\ObjectStorage.
How do i get a \TYPO3\CMS\Extbase\Persistence\ObjectStorage from the uid of the category?
Thanks!
You need a setter method for the categories like this:
public function addCategory($category)
{
$this->categories->attach($category);
}
This method will add one model to your object storage.
As you need the category model to be added, you need to get the corresponding model of the uid with $categoryRepository->findByUid($uid);
I tried to integrate an existing table to my extension. The problem is that the content of the table isn't taken over. I created a new model with the name of the existing table and named the properties according to the existing column names. I also implemented the corresponding getters and setters of the properties.
The name of the existing table is tx_institutsseminarverwaltung_domain_model_event.
What is my failure in this case? Just want to access the data of an existing table from another extension.
Thanks in advance.
UPDATE:
I tried this:
/**
* Protected Variable objectManager wird mit NULL initialisiert.
*
* #var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
* #inject
*/
protected $objectManager = NULL;
and listAction():
/**
* action list
*
* #return void
*/
public function listAction() {
echo "test";
$theRepository = $this->objectManager->get('\TYPO3\institutsseminarverwaltung\Domain\Repository\EventRepository');
$yourRecords = $theRepository->findAll();
$this->view->assign('events', $yourRecords);
}
But no results returned.
You should use the repository linked to this table. Something like this :
$theRepository = $this->objectManager->get(\Your\VendorName\Domain\Repository\TheRepository::class);
$yourRecords = $theRepository->findAll();
How are you trying to "consume" or access the data from the other table in your extension?
Do you have a repository for the existing table (maybe there is already an existing repository, that you can reuse)?
See german typo3 board mapping existing tables and SO thread TYPO3 / How to make repository from existing table fe_users?
solution is:
$querySettings = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Typo3QuerySettings');
$querySettings->setRespectStoragePage(FALSE);
$theRepository = $this->objectManager->get('TYPO3\\institutsseminarverwaltung\\Domain\\Repository\\EventRepository');
$theRepository->setDefaultQuerySettings($querySettings);
$yourRecords = $theRepository->findAll();
$this->view->assign('events', $yourRecords);
I have Eloquent Event model, which is related towards multiple dates like this:
$event->dates // shows Collection of 8 Eloquent date models
After that i need to pick the only date, what is closest to current time. I know how to do this using query of raw SQL, or DB class. But isnt there any better solution? I dont want to jump into database for data, I already have.
Date format in eloquent models is surprisingly string.
You can use what we call in laravel mutators like this ->
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Event extends Model
{
public function dates()
{
return $this->hasMany('Date');
}
/**
* Get Dates for the event.
*
* #param string $value
* #return array
*/
public function getDates()
{
$dates = $this->dates()->getQuery()->orderBy('created_at', 'asc')->get();
return $dates;
}
}
Hope this helps.
UPDATE
I think now you can also directly do this in the model definition like this -
return $this->hasMany('Date')->orderBy('created_at', 'asc')
I have a Sphinx search engine running on MySQL protocol and I use Phalcon\Db\Adapter\Pdo\Mysql to connect to it. Sphinx tables are implemented as models.
When I try to select (using SpinxQL) I, obviously, get an error when database adapter attempts to extract table metadata running queries against tables which are not supported and not present respectively in SpinxQL. There is a workaround in the documentation showing how to manually assign metadata... But being to lazy by nature I want to try to automate metadata generation.
I assume that metadata is produced by the database adapter, probably as a result of calling getColumnsList() on the instance following getColumnDefinition() or something else (???). Is this my assumption correct? I want is to extend Phalcon\Db\Adapter\Pdo\Mysql and override those methods to be compatible with Sphinx.
Thanks in advance for your suggestions!
Ok, you need to override at least two methods to make this work, the following class would work:
<?php
class SphinxQlAdapter extends Phalcon\Db\Adapter\Pdo\Mysql implements Phalcon\Db\AdapterInterface
{
/**
* This method checks if a table exists
*
* #param string $table
* #param string $schema
* #return boolean
*/
public function tableExists($table, $schema=null)
{
}
/**
* This method describe the table's columns returning an array of
* Phalcon\Db\Column
*
* #param string $table
* #param string $schema
* #return Phalcon\Db\ColumnInterface[]
*/
public function describeColumns($table, $schema=null)
{
}
}
Then in your connection, you use the new adapter:
$di->set('db', function(){
return new SphinxQlAdapter(
//...
);
});
I have a php object mapping to a mongodb document(called Node) with a structure
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
class Node{
/**
* #MongoDB\Id
*/
protected $id;
/**
* #MongoDB\String
*/
protected $domain;
/**
* #MongoDB\ReferenceMany(targetDocument="NodeItem",cascade=
* {"persist"},simple="true")
*/
protected $items = array();
//getter and setters below
}
And a referenced document called, NodeItem,
class NodeItem {
/**
* #MongoDB\Id
*/
protected $id;
/**
* #MongoDB\String
*/
protected $name;
/**
* #MongoDB\ReferenceOne(targetDocument="Node", cascade={"persist"},
* simple="true")
*/
protected Node;
//setter and getters
}
As reflected by the annotations above 'Node' references MANY 'NodeItems' stored in a $items array and 'NodeItems' references ONE 'Node'. So those are bi-directional referenced collections.
My Question is how to effectively delete a few 'NodeItem' documents from its collection (based on the array of available ids), so that the deleted NodeItem documents are also deleted from the $items array references in 'Node' (cascaded delete I think is what I am asking for?).
I wrote a function that has code like this :
$qb = $this->dm->createQueryBuilder('SomeBundleBundle:NodeItem');
/*
* deletes from NodeItem collection
*/
foreach($NodeItemsArray as $itemId){
$qb->remove()->field('id')->equals($itemId)->getQuery()->execute();
}
But the above function only deletes the documents from NodeItem collection, but the associated items in the $items array of 'Node' are not deleted. Also, the {cascade:persist} in the annotations doesn't seem to help. The code is implemented in Symfony 2 framework
Some help is appreciated !
The only way to achieve that is with a listener on the onRemove event.
But has mentioned by #jmikola, you'll have to use the $dm->remove() method, and not the QueryBuilder (since it doesn't support events yet).
so, to delete the Item do:
//Get the NodeItem you want in the items array and delete it:
$items = $node->getItems();
$dm->remove($items->get(2)); //Remove the third item as an example
And register the event:
class CascadeNodeDeleterListener {
public function preRemove(LifecycleEventArgs $eventArgs) {
$odm = $eventArgs->getDocumentManager(); /* #var $odm DocumentManager */
$object = $eventArgs->getDocument();
if($object instanceOf NodeItem) {
$node = $object->getNode();
$items = $node->getItems();
$items->removeElement($object);
$class = $dm->getClassMetadata(get_class($node));
$dm->getUnitOfWork()->recomputeSingleDocumentChangeSet($class, $node);
}
}
}
In services.yml:
<service id="listener" class="CascadeNodeDeleterListener">
<tag name="doctrine.common.event_listener" event="onRemove" />
</service>
See Doctrine ODM Events from more info.
Cascade behavior in ODM is only respected by UnitOfWork operations. MongoDB does not natively support cascades and triggers (yet, anyway). In your case, query builder will construct and execute a query like the following:
db.node_items.remove({"_id": ObjectId("...")})
UnitOfWork is not involved at all (there are no staged operations or flushing) and no cascade is triggered.
On the other hand, say you had a managed $nodeItem object. Passing it to DocumentManager::remove() would invoke UnitOfWork and cause any referenced documents mapped with cascade=REMOVE or cascade=ALL to also be removed. Of course, you'd have to call flush() to execute the operations in MongoDB.
Based on your current code, the only operation that will be cascaded is DocumentManager::persist(). In practice, I assume you'd create a Node, construct and add a few NodeItems to it, and persist the Node (allowing its items to be persisted automatically).
If NodeItems only ever belong to a single Node, you may want to avoid cascade=REMOVE and simply do $nodeItem->getNode()->getItems()->removeElement($nodeItem) after you remove the $nodeItem itself, but before flush().
Also, I noticed you're initializing your collection field to an array. Later on, ODM is going to hydrate this field as a Doctrine\ODM\MongoDB\PersistentCollection instance, which could lead to ambiguity. As a best practice, you should initialize such fields as Doctrine\Common\Collections\ArrayCollection in your constructor. That way, you can always expect them to be Collection instances.