Call to a member function all() on array in laravel - mongodb

I am getting this error:
FatalErrorException in Builder.php line 485:
Call to a member function all() on array
my register controller
namespace App\Http\Controllers\Auth;
use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Http\Request;
class RegisterController extends Controller
{
/*
|--------------------------------------------------------------------------
| Register Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users as well as their
| validation and creation. By default this controller uses a trait to
| provide this functionality without requiring any additional code.
|
*/
use RegistersUsers;
/**
* Where to redirect users after registration.
*
* #var string
*/
protected $redirectTo = '/';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest');
}
/**
* Get a validator for an incoming registration request.
*
* #param array $data
* #return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'fullname' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|min:6',
]);
}
/**
* Create a new user instance after a valid registration.
*
* #param array $data
* #return User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['fullname'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
}
/**
* Handle a registration request for the application.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function register(Request $request)
{
$validator = $this->validator($request->all());
if ($validator->fails()) {
$this->throwValidationException(
$request, $validator
);
}
$user = $this->create($request->all());
return redirect($this->redirectPath());
}
}

You need to update jenssegers/mongodb.
Looking at https://github.com/jenssegers/laravel-mongodb the compatability charts shows that 2.3 doesn't satisfy Laravel 5.3+.
The reason you're getting that specific error is because in Laravel 5.3 a change was made to the query builder so it would return a collection instead of an array, however, 2.3 of jenssegers/mongodb just returns an array. In version 3.1 of jenssegers/mongodb there is now a check to determine which version of Laravel you're using for this reason.
Hope this helps!

Related

TYPO3 updateAction not called

I have TYPO3 7.6.18
that's my action. When I submit form this action not called!
/**
* action update
*
* #param \Fhk\Feusersplus\Domain\Model\User $user
*/
public function updateAction(\Fhk\Feusersplus\Domain\Model\User $user) {
die();
}
but this varian works, when I set another type.
/**
* action update
*
* #param array $user
*/
public function updateAction(array $user) {
// var_dump($user);
die();
// parent::updateAction($user);
}
Where may be problem? People help please. I really have not any ideas (
Problem was because I did't set right converter for my 'date' field.

Form post-processing in Symfony2

I am new of Symfony, and I am trying to create a form bound to an Entity User.
One field of this entity is of type ArrayCollection. It is actually a OneToMany relationship with objects of another class.
So, a little bit of code just to be clearer.
class User
{
\\...
/**
* #ORM\OneToMany(targetEntity="UserGoods", mappedBy="users")
* #ORM\JoinColumn(name="goods", referencedColumnName="id")
*/
private $goods;
public function __construct()
{
$this->goods = new ArrayCollection();
}
\\...
}
And the associated class
class UserGoods
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var \DateTime
*
* #ORM\Column(name="inserted_at", type="datetime")
*/
private $insertedAt;
/**
* #var float
*
* #ORM\Column(name="value", type="float")
*/
private $value;
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="goods")
*/
protected $users;
}
Now, I want to create a FormBuilder that does something extremely simple, yet I couldn't figure it out how to do it by myself.
I want just a field of type number, and if an object of type Goods with the current date exists, modify it, otherwise add a new object to the collection.
This could be easily done inside the controller, but I have a lot of instances of this form, and this would make my program impossible to maintain.
Is there a way to add some post-processing of submitted data inside the form builder?
I already tried with DataTransformers but these won't suffice, as at most they would transform a number to a UserGoods object, and the original ArrayCollection would not be preserved (and what about doctrine associations?).
In addition, if I declare the field type as collection of number types, all the items inside the ArrayCollection would be displayed when rendering the form, not just the last one.
Any idea on how to get out of this?
Thank you in advance for your help.
As suggested, use Form Events. Inside the event you will check if the Goods with the submitted date already exist (load them from database) and your will modify them with the post data. If they dont exist, you will be creating new ones. You can also make another method in your entity, getLastItemsInCollection(), where you can use Criteria, to only load the last one from the database (recommended), or get the last item from original ArrayCollection. You can make a field unmapped, and map the Goods manually in the FormEvent, as described above. I hope that helps and I hope I understood correctly.
I followed Cerad and tomazahlin suggestions and I came up with a solution.
I am sure that every year at least 2 people over the world share my same problem, so I'll take some time to post my outcome.
Feel free to correct, criticize or add me, in the end I am a newbie of Symfony!
First, how I defined my two classes in the end.
class User
{
//...
/**
* #ORM\ManyToMany(targetEntity="UserGoods", inversedBy="users", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="goods", referencedColumnName="id")
*/
// Should have been a OneToMany relationship, but Doctrine requires the
// owner side to be on the Many side, and I need it on the One side.
// A ManyToMany relationship compensate this.
private $goods;
public function __construct()
{
$this->goods = new ArrayCollection();
}
//...
}
And the connected class
/**
* #ORM\HasLifecycleCallbacks()
**/
class UserGoods
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var \DateTime
*
* #ORM\Column(name="inserted_at", type="datetime")
*/
private $insertedAt;
/**
* #var float
*
* #ORM\Column(name="value", type="float", nullable=true)
*/
// I do not want this field to be null, but in this way when
// persisting I can look for null elements and remove them
private $value;
/**
* #ORM\ManyToMany(targetEntity="User", inversedBy="goods")
*/
protected $users;
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
// This automatically sets InsertedAt value when inserting or
// updating an element.
public function setInsertedAtValue()
{
$date = new \DateTime();
$this->setInsertedAt( $date );
}
}
As I said, I wanted a FormBuilder to handle my array collection. The best form type for this purpose is... collection type.
This require a subform to be defined as its type.
<?php
namespace MyBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use MyBundle\Entity\UserGoods;
class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('goods', 'collection', array(
'type' => new GoodsdataWithDateType(),
'required' => false,
)
);
\\ ...
And the subform.
Since I need only the today's value to be displayed, and not all of them, I also need to add a FormEvent clause to check which items to insert.
namespace MyBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
class GoodsdataWithDateType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
// Here I add the event listener:
// Since I want only today's value to be displayed, I implement
// a check on this field of each element
$builder->addEventListener(
FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$goods = $event->getData();
$form = $event->getForm();
$datetime1 = $goods->getInsertedAt();
$datetime2 = new \DateTime();
$datetime2->setTime(0, 0, 0);
if ($datetime1 > $datetime2)
{
$form->add('value', 'number', array(
'required' => false,
));
// I am setting this value with LifecycleCallbacks, and I do not
// want the user to change it, I am adding it commented just for
// completeness
// $form->add('insertedAt', 'date', array(
// 'widget' => 'single_text',
// 'format' => 'yyyy,MM,dd',
// ));
}
});
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'MyBundle\Entity\UserGoods',
));
}
public function getName()
{
return 'goodsdatawithdate';
}
}
This works fine, but is displayed very badly when rendered with something like {{ form(form) }} in twig files.
To make it more user-friendly, I customized how the form was presented, in order to remove some garbage and include only the labels that were necessary.
So in my twig:
{{ form_start(form) }}
{{ form_errors(form) }}
<div>
{{ form_label(form.goods) }}
{{ form_errors(form.goods) }}
<br>
{% for field in form.goods %}
{{ form_widget(field) }}
{% endfor %}
</div>
{{ form_end(form) }}
This is nice so far, but I also want to include new elements in my collection, in particular if today's good has not been inserted yet.
I can do this inside my FormBuilder, by manually add a new item in the array before calling the $builder.
class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$thisuser = $builder->getData();
// I added the following function inside the User class.
// I use a for loop to scroll all the associated Goods to get the
// latest one.
$mygoods = $thisuser->getLatestGoods();
if ( $mygoods && null !== $mygoods->getId() ) {
// The Array contains already some elements
$datetime1 = $mygoods->getInsertedAt();
$datetime2 = new \DateTime();
$datetime2->setTime(0, 0, 0);
// Check when was the last one inserted
if ($datetime1 < $datetime2) // Nice way to compare dates
{
// If it is older than today, add a new element to the array
$newgoods = new UserGoods();
$thisuser->addGoods($newgoods);
}
} else {
// The array is empty and I need to create the firs element
$newgoods = new UserGoods();
$thisuser->addGoods($newgoods);
}
$builder->add('goods', 'collection', array(
'type' => new GoodsdataWithDateType(),
'required' => false,
'allow_add' => true, // this enables the array to be
// populated with new elements
)
);
But I also want that if a user removes an inserted value (i.e., inserts nothing in the form), the associated array element should be removed.
Allowing the user to remove elements is a little bit trickyer. I cannot rely on 'allow_delete' property, since by working only with the last item in the collection, all the previous ones would be removed when the form is submitted.
I cannot rely on LifecycleCallbacks neither, because the changes made to relationships are not persisted in the database.
Thankfully to open source, I found a post here that helped me.
What I needed was an EventListener on Doctrine Flush operations.
namespace MyBundle\EventListener;
use Doctrine\ORM\Event\OnFlushEventArgs;
use MyBundle\Entity\UserGoods;
class EmptyValueListener
{
public function onFlush(OnFlushEventArgs $args)
{
$em = $args->getEntityManager();
$uow = $em->getUnitOfWork();
$entities = array_merge(
$uow->getScheduledEntityInsertions(),
$uow->getScheduledEntityUpdates()
);
foreach ($entities as $entity) {
if ($entity instanceof UserGoods) {
if ($entity && null !== $entity )
{
if ( empty($entity->getValue()) )
{
$users = $entity->getUsers();
foreach ($users as $curruser)
{
$curruser->removeGoods($entity);
$em->remove($entity);
$md = $em->getClassMetadata('MyBundle\Entity\UserGoods');
$uow->computeChangeSet($md, $entity);
$em->persist($curruser);
$md = $em->getClassMetadata('MyBundle\Entity\User');
$uow->computeChangeSet($md, $curruser);
}
}
}
}
}
}
}
and registered it in my config.yml as
mybundle.emptyvalues_listener:
class: MyBundle\EventListener\EmptyValueListener
tags:
- { name: doctrine.event_listener, event: onFlush }

zend 2 + doctrine 2 hydrator - the hydrator is not hydratating POST objects

I am having problems getting my doctrine hydrator to hydrate my return post forms.
Post forms.
I keep getting the following message:
An exception occurred while executing 'INSERT INTO worker_essay
(title) VALUES (?)' with params [null]: SQLSTATE[23000]: Integrity
constraint violation: 1048 Column 'title' cannot be null
but this cannot be correct because I have a validator on my form requiring this value to be inserted, yet my form is validating.
I would really appreciate any help or advice on resolving the problem or advice on how to go about discovering what is causing the problem.
public function getInputFilterSpecification()
{
return array(
'title' => array(
'required' => true
),
);
}
these are the var_dumped values from the returned form:
object(Zend\Stdlib\Parameters)[146] public 'WorkerStatement' =>
array (size=2)
'id' => string '' (length=0)
'title' => string 'the values from title' (length=21) public 'submit' => string 'Submit' (length=6)
As you can see, the values are clearly there, which means that the problem might be in the hydrators.
I now enclosed the rest of the documents.
The Controller
public function workerStatementAction()
{
$form = new CreateWorkerStatementForm($this->getEntityManager());
$workerStatement = new WorkerStatement();
// $form->setInputFilter($workerEssay->getInputFilter());
$form->bind($workerStatement);
// var_dump($workerStatement); die();
if ($this->request->isPost()) {
$post = $this->request->getPost();
$form = $form->setData($this->request->getPost());
if ($form->isValid()) {
$post =$this->request->getPost();
$this->getEntityManager()->persist($workerStatement);
$this->getEntityManager()->flush();
// Redirect to list of aboutyou
return $this->redirect()->toRoute('worker');
}
}
return array('form' => $form);
}
The fieldset
class WorkerStatementFieldset extends Fieldset implements InputFilterProviderInterface
{
public function __construct(ObjectManager $objectManager)
{
parent::__construct('WorkerStatement');
$this->setHydrator(new DoctrineHydrator($objectManager, 'Workers\Entity\WorkerStatement'))
->setObject(new WorkerStatement());
$this->add(array(
'name' => 'title',
'type' => 'Zend\Form\Element\Text',
'options' => array(
'label' => 'title',
),
));
}
** The Form**
class CreateWorkerStatementForm extends Form
{
public function __construct(ObjectManager $objectManager)
{
parent::__construct('WorkerStatement');
// The form will hydrate an object of type "AboutYou"
$this->setHydrator(new DoctrineHydrator($objectManager, 'Workers\Entity\WorkerStatement'));
// Add the user fieldset, and set it as the base fieldset
$workerStatementFieldset = new WorkerStatementFieldset($objectManager);
$workerStatementFieldset->setUseAsBaseFieldset(true);
$this->add($workerStatementFieldset);
}
}
Here is the var_daump of the persist in the controller:
$this->getEntityManager()->persist($workerStatement);
object(Workers\Entity\WorkerStatement)[351]
protected 'id' => null
protected 'title' => null
You will note that they are empty, yet the var dump of the values from the returned post clearly contain the values.
I enclose my workstatement class. you will note that I have used the magic getter/setter.
<?php
namespace Workers\Entity;
use Doctrine\ORM\Mapping as ORM;
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\Factory as InputFactory;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
/**
*
* #ORM\Entity
* #ORM\Table(name="worker_essay")
* #property string $title
*/
class WorkerStatement
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string")
*/
protected $title;
/**
* Magic getter to expose protected properties.
*
* #param string $property
* #return mixed
*/
public function __get($property)
{
return $this->$property;
}
/**
* Magic setter to save protected properties.
*
* #param string $property
* #param mixed $value
*/
public function __set($property, $value)
{
$this->$property = $value;
}
public function getInputFilterSpecification()
{
return array(
'title' => array(
'required' => true
)
);
}
}
DoctrineHydrator by default is hydrating and extracting values using getters and setters. If your entity doesn't have these methods then it cannot work properly. If you dont' want to use getters/setters, use new DoctrineHydrator($objectManager, 'Workers\Entity\WorkerStatement', false) instead of new DoctrineHydrator($objectManager, 'Workers\Entity\WorkerStatement').
Maybe it's not the reason why hydrator doesn't work. Please edit your first post and paste Workers\Entity\WorkerStatement class.
EDIT
Hydrator is calling getTitle() and your magic method is trying to access getTitle property which doesn't exist. You have three options:
Change DoctrineHydrator to new DoctrineHydrator($objectManager, 'Workers\Entity\WorkerStatement', false).
Add getters and setters. For example getTitle(), setTitle($title).
Refactor magic methods to accept getProperty, setProperty.
Actually You dont need to add the hydrator in the form , use it in the controller (or service) if its necessary .
plz add a var dump before :
$this->getEntityManager()->persist($workerStatement);
and post the result

Creating multiple models

I'm using Zend Framework and implementing Domain Model. I have Models, Mappers and DbTables.
Suppose we should fetch multiple rows from database or fetch form data where we should create multiple models and populate that models from database rows or form.
Should I implement fetching and creation of models in Mapper and then call that method from Controller? Or I should implement this in Model?
Is it okay to initialize Mapper in Controller?
The short answer is YES!
If you need to get anything from the database you almost have use the mapper somewhere, because ideally the domain model should not be aware of the database at all or event hat a mapper exists really.
There are I'm sure many strategies and patterns for using and accessing domain models and mappers. I'm also sure that everyone will have differing opinions on how best to utilize these resources. The bottom line is that you have to use what you know how to use, you can always refactor later when you know more.
Just by way of example I'll include a base mapper and a base entity(domain) model.
<?php
/**
* Base mapper model to build concrete data mappers around.
* Includes identity map functionallity.
*/
abstract class My_Application_Model_Mapper
{
protected $_tableGateway = NULL;
protected $_map = array();
/**
* Will accept a DbTable model passed or will instantiate
* a Zend_Db_Table_Abstract object from table name.
*
* #param Zend_Db_Table_Abstract $tableGateway
*/
public function __construct(Zend_Db_Table_Abstract $tableGateway = NULL) {
if (is_null($tableGateway)) {
$this->_tableGateway = new Zend_Db_Table($this->_tableName);
} else {
$this->_tableGateway = $tableGateway;
}
}
/**
* #return Zend_Db_Table_Abstract
*/
protected function _getGateway() {
return $this->_tableGateway;
}
/**
* #param string $id
* #param object $entity
*/
protected function _setMap($id, $entity) {
$this->_map[$id] = $entity;
}
/**
* #param string $id
* #return string
*/
protected function _getMap($id) {
if (array_key_exists($id, $this->_map)) {
return $this->_map[$id];
}
}
/**
* findByColumn() returns an array of rows selected
* by column name and column value.
* Optional orderBy value.
*
* #param string $column
* #param string $value
* #param string $order
* #return array
*/
public function findByColumn($column, $value, $order = NULL) {
$select = $this->_getGateway()->select();
$select->where("$column = ?", $value);
if (!is_null($order)) {
$select->order($order);
}
$result = $this->_getGateway()->fetchAll($select);
$entities = array();
foreach ($result as $row) {
$entity = $this->createEntity($row);
$this->_setMap($row->id, $entity);
$entities[] = $entity;
}
return $entities;
}
/**
* findById() is proxy for find() method and returns
* an entity object. Utilizes fetchRow() because it returns row object
* instead of primary key as find() does.
* #param string $id
* #return object
*/
public function findById($id) {
//return identity map entry if present
if ($this->_getMap($id)) {
return $this->_getMap($id);
}
$select = $this->_getGateway()->select();
$select->where('id = ?', $id);
//result set, fetchRow returns a single row object
$row = $this->_getGateway()->fetchRow($select);
//create object
$entity = $this->createEntity($row);
//assign object to odentity map
$this->_setMap($row->id, $entity);
return $entity;
}
/**
* findAll() is a proxy for the fetchAll() method and returns
* an array of entity objects.
* Optional Order parameter. Pass order as string ie. 'id ASC'
* #param string $order
* #return array
*/
public function findAll($order = NULL) {
$select = $this->_getGateway()->select();
if (!is_null($order)) {
$select->order($order);
}
$rowset = $this->_getGateway()->fetchAll($select);
$entities = array();
foreach ($rowset as $row) {
$entity = $this->createEntity($row);
$this->_setMap($row->id, $entity);
$entities[] = $entity;
}
return $entities;
}
/**
* Abstract method to be implemented by concrete mappers.
*/
abstract protected function createEntity($row);
}
Here is the base domain object:
<?php
/**
* Base domain object
* includes lazy loading of foreign key objects.
*/
abstract class My_Application_Model_Entity_Abstract
{
protected $_references = array();
/**
* Accepts an array to instantiate the object, else use
* __set() when creating objects
* #param array $options
*/
public function __construct(array $options = NULL) {
if (is_array($options)) {
$this->setOptions($options);
}
}
/**
* #param array $options
* #return \My_Application_Model_Entity_Abstract
*/
public function setOptions(array $options) {
$methods = get_class_methods($this);
foreach ($options as $key => $value) {
$method = 'set' . ucfirst($key);
if (in_array($method, $methods)) {
$this->$method($value);
}
}
return $this;
}
/**
* Map the setting of non-existing fields to a mutator when
* possible, otherwise use the matching field
*/
public function __set($name, $value) {
$property = '_' . strtolower($name);
if (!property_exists($this, $property)) {
throw new \InvalidArgumentException("Setting the property '$property'
is not valid for this entity");
}
$mutator = 'set' . ucfirst(strtolower($name));
if (method_exists($this, $mutator) && is_callable(array($this, $mutator))) {
$this->$mutator($value);
} else {
$this->$property = $value;
}
return $this;
}
/**
* Map the getting of non-existing properties to an accessor when
* possible, otherwise use the matching field
*/
public function __get($name) {
$property = '_' . strtolower($name);
if (!property_exists($this, $property)) {
throw new \InvalidArgumentException(
"Getting the property '$property' is not valid for this entity");
}
$accessor = 'get' . ucfirst(strtolower($name));
return (method_exists($this, $accessor) && is_callable(array(
$this, $accessor))) ? $this->$accessor() : $this->$property;
}
/**
* Get the entity fields.
*/
public function toArray() {
//TODO
}
/**
* set and get for _references array, allows the potential to lazy load
* foreign objects.
*/
public function setReferenceId($name, $id) {
$this->_references[$name] = $id;
}
public function getReferenceId($name) {
if (isset($this->_references[$name])) {
return $this->_references[$name];
}
}
}
I have referenced many tutorials and books to finally get my head around these concepts and techniques.
The use of these objects is as needed, if you need to pull an object from the DB you call the mapper, if you need to build an object with form data (or some other data) you can call the object directly.
I hope this helps some. Good Luck!
I use the same architecture and design patterns in all my ZF work. Your mappers should be the only classes in your whole system that access the database. This ensures good Separation of Concerns.
I've toyed a bit with using thin wrapper methods in my Models, such as:
class Application_Model_Foo {
public function save() {
$mapper = $this->_getMapper();
$mapper->save($this);
}
}
This enables me to call something like:
$foo = new Application_Model_Foo();
$foo->setBar('baz-bum');
$foo->save();
But this makes testing more complicated and muddies the water when it comes to SoC. Lately I've been removing such occurrences from my code in favor of just calling up the mapper directly, as in:
$foo = new Application_Model_Foo();
$foo->setBar('baz-bum');
$mapper = new Application_Model_FooMapper();
$mapper->save($foo);
The latter example means one more line of code in my controller method, but for simplicity in testing I think it's worth it.

Extbase stores empty values in database

I am trying to create an object, but the values are not stored into the database. This is done on an "index"-action because the plugin is inserted via TypoScript and actually does not create output. So there is no object given when calling the action, that's why I am creating it by myself.
$stat = new Tx_MyExt_Domain_Model_Stat;
$stat->setSubscriberId($_COOKIE['statid']);
$stat->setDomain($_SERVER['HTTP_HOST']);
$stat->setRequestUri($_SERVER['REQUEST_URI']);
$this->statRepository = t3lib_div::makeInstance('Tx_myExt_Domain_Repository_StatRepository');
$this->statRepository->add($stat);
doing a var_dump($stat) gives the following:
object(Tx_MyExt_Domain_Model_Stat)#191 (9) {
["subscriber_id":protected]=>
string(1) "2"
["domain":protected]=>
string(22) "test.localhost.example"
["request_uri":protected]=>
string(26) "/testpage/index.php?id=2"
["uid":protected]=>
NULL
["_localizedUid":protected]=>
NULL
["_languageUid":protected]=>
NULL
["pid":protected]=>
NULL
["_isClone":"Tx_Extbase_DomainObject_AbstractDomainObject":private]=>
bool(false)
["_cleanProperties":"Tx_Extbase_DomainObject_AbstractDomainObject":private]=>
NULL
}
So this looks like the values are assigned properly. But when looking into the database, I get this:
uid pid subscriber_id domain request_uri crdate
13 0 0 NULL NULL 1328176026
Repository:
class Tx_MyExt_Domain_Repository_StatRepository extends Tx_Extbase_Persistence_Repository
{}
Model:
class Tx_MyExt_Domain_Model_Stat extends Tx_Extbase_DomainObject_AbstractEntity
{
/**
* #var int
* #dontvalidate
*/
protected $subscriber_id = 0;
/**
* #var string
* #dontvalidate
*/
protected $domain = '';
/**
* #var string
* #dontvalidate
*/
protected $request_uri = '';
/**
* #param int $susbcriber_id Subscriber id
* #return void
*/
public function setSubscriberId($subscriber_id)
{
$this->subscriber_id = $subscriber_id;
}
/**
* #return int Susbcriber id
*/
public function getSubscriberId()
{
return $this->subscriber_id;
}
/**
* #param string $domain Domain
* #return void
*/
public function setDomain($domain)
{
$this->domain = $domain;
}
/**
* #return string Domain
*/
public function getDomain()
{
return $this->domain;
}
/**
* #param string $request_uri Request URI
* #return void
*/
public function setRequestUri($request_uri)
{
$this->request_uri = $request_uri;
}
/**
* #return string Request URI
*/
public function getRequestUri()
{
return $this->request_uri;
}
}
Can someone give me advise what may be wrong here?
Debugged through the whole extbase process. It seems that in typo3/sysext/extbase/Classes/Persistence/Backend.php, the attributes are skipped on this line:
if (!$dataMap->isPersistableProperty($propertyName) || $this->propertyValueIsLazyLoaded($propertyValue)) continue;
This because $dataMap->isPersistableProperty($propertyName) doesn't return something. Investigating in typo3/sysext/extbase/Classes/Persistence/Mapper, there is:
/**
* Returns TRUE if the property is persistable (configured in $TCA)
*
* #param string $propertyName The property name
* #return boolean TRUE if the property is persistable (configured in $TCA)
*/
public function isPersistableProperty($propertyName) {
return isset($this->columnMaps[$propertyName]);
}
So the solution is quite simple: create a valid TCA. I didn't had one (or a too minimalistic) since the table i am using is not going to be displayed in the backend.
While misconfiguration of TCA might be causing the problem, there might be others. For example, extbase does not like it when you are defining unique keys and fails silently.
Having struggeld with the problems in multiple projects, I am now using the following debugging routine for projects made with the extension builder
Remove your own additions from the table related classes and as well from typoscript. This has to be done for ext_tables.php, ext_tables.sql, all files in Configuration/TCA and Configuration/Typoscript if you have changed their state in Configuration/ExtensionBuilder/settings.yaml to merge or keep.
Check if your application now does save. If not, report a detailed bug report to exentension builder.
Normally your application should save now. Readd recursively the changes you've made until you find the error. Start with ext_tables.sql (don't forget you have to remove and readd the database every time), go on with ext_tables.php, Configuration/TCA/* and end with Configuration/Typoscript (it's my personal experience that these order is the fastest)
Report your stuff to the extbase team and add it to this thread (as it's the first google hit when you experience the error)