TYPO3 updateAction not called - typo3

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.

Related

Dynamic recipient in form

I have a custom extension with list and detail of teachers. On the detail page I include a form with code:
<formvh:render persistenceIdentifier="1:/form_definitions/myform.yaml" />
I need to set the recipient with the teacher's email shown on the page. How can I do?
You can achieve that by writing a custom form finisher.
Add a hidden field to your form which holds the the ID of the teacher
Fetch that id in your form finisher and load the Teacher model by your repository
A (not complete) example of a form finisher, which loads recipient data from a custom model and sends the mail to this specific data:
class EmailToContactPersonFinisher extends EmailFinisher
{
/**
* Executes this finisher
* #see AbstractFinisher::execute()
*
* #throws FinisherException
*/
protected function executeInternal()
{
/** #var FormRuntime $formRuntime */
$formRuntime = $this->finisherContext->getFormRuntime();
if ($formRuntime->getResponse()->getRequest()) {
if ($formRuntime->getResponse()->getRequest()->hasArgument('contactPerson')) {
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
/** #var ContactPersonRepository $repository */
$contactPersonRepository = $objectManager->get(ContactPersonRepository::class);
/** #var ContactPerson $contactPerson */
$contactPerson = $contactPersonRepository->findByUid($formRuntime->getResponse()->getRequest()->getArgument('contactPerson'));
}
}
// override contactPerson related options
if ($contactPerson instanceof ContactPerson) {
if ($contactPerson->getEmail()) {
$recipientAddress = $contactPerson->getEmail();
}
}
$this->setOption('recipientAddress', $recipientAddress);
parent::executeInternal();
}
}
You can also have a look at the standard emailFinisher, which gives you quick idea on the architecture.
sysext/form/Classes/Domain/Finishers/EmailFinisher.php

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

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!

Call to undefined method getPosition() - Why and Fix

I made an extbase extension with a class Appointment with a property expertises und another one subExpertises of the same type.
This is how they look like in the Appointment class (subExpertises is the same):
/**
* expertises
*
* #var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<...\Domain\Model\Expertise>
*/
protected $expertises = NULL;
/**
* Adds an expertise
*
* #param ...\Domain\Model\Expertise $expertise
* #return void
*/
public function addExpertise(...\Domain\Model\Expertise $expertise) {
$this->expertises->attach($expertise);
}
I get an error when executing this code in my controller after editing the appointment in a fluid form:
/**
*
* #param \Domain\Model\Appointment $appointment
* #return void
*/
public function bookAction(\Domain\Model\Appointment $appointment) {
//empty all expertises of appointment - then fill them with the selected from lawyer
$appointment->setExpertises(new \TYPO3\CMS\Extbase\Persistence\ObjectStorage());
$appointment->setSubExpertises(new \TYPO3\CMS\Extbase\Persistence\ObjectStorage());
//add all checked expertises of lawyer to appointment
foreach ($appointment->getLawyer()->getExpertises() as $expertise) {
if ($expertise->getChecked()) {
$appointment->addExpertise($expertise);
}
foreach ($expertise->getSubExpertises() as $subExpertise) {
if ($subExpertise->getChecked()) {
$appointment->addSubExpertise($subExpertise);
}
}
}
$this->appointmentRepository->update($appointment);
}
This is the error:
Fatal error: Call to undefined method \Domain\Model\Expertise::getPosition() in /var/www/typo3_src/typo3_src-6.2.25/typo3/sysext/extbase/Classes/Persistence/Generic/Backend.php on line 453
Now it seems that TYPO3 thinks Expertise is of type ObjectStorage because it tries to call getPosition() but I have no clue why it does that and what I should change in order to successfully save my Appointment object with the new Expertises.
I tried debugging the appointment object, but I couldn't find the problem - it seems okay to me, it just shows that expertises und subExpertises have been modified.
Getter methods in Extbase aren't magic, you have to explicitly define them.
If you're dealing with a n:n-relation, you also need to initialize the Property as ObjectStorage in your model and configure it in the TCA.
/**
* Initialize all ObjectStorage properties.
*
* #return void
*/
protected function initStorageObjects() {
$this->yourProperty = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
}

[Symfony][Form] Add validator/constraint to property only if it has changed

I've got the following scenario: I'm validating appointments and there's a custom validator, which tells the user if his choosen date is valid or not. It's not valid, if the date is already blocked by another entity. This works flawlessly on adding new entities.
Now I'd like to trigger the date validation on edit only if the date itself has changed. So just changing the title of the appointment should not validate the date.
My entity class:
use Doctrine\ORM\Mapping as ORM;
use Acme\Bundle\Validator\Constraints as AcmeAssert;
/**
* Appointment
*
* #ORM\Entity
* #AcmeAssert\DateIsValid
*/
class Appointment
{
/**
* #ORM\Column(name="title", type="string", length=255)
*
* #var string
*/
protected $title;
/**
* #ORM\Column(name="date", type="date")
*
* #var \DateTime
*/
protected $date;
}
The validator class (used as a service):
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
/**
* Validates the date of an appointment.
*/
class DateIsValidValidator extends ConstraintValidator
{
/**
* {#inheritdoc}
*/
public function validate($appointment, Constraint $constraint)
{
if (null === $date = $appointment->getDate()) {
return;
}
/* Do some magic to validate date */
if (!$valid) {
$this->context->addViolationAt('date', $constraint->message);
}
}
}
The corresponding Constraint class is set to target the entity class.
use Symfony\Component\Validator\Constraint;
/**
* #Annotation
*/
class DateIsValid extends Constraint
{
public $message = 'The date is not valid!';
/**
* {#inheritdoc}
*/
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
/**
* {#inheritdoc}
*/
public function validatedBy()
{
return 'acme.validator.appointment.date';
}
}
Now I don't find a clean way to depend on a date change. I could simply track the old date in my entity, but that doesn't feel like a proper solution, if I'd like to implement more complex constraints. :[
Cheers
Since symfony 2.3 you can use Form Events to solve this problem. I added the change-check code to my FormType, by storing (and cloning) the original entity at the form creation.
Then added a POST_SUBMIT event listener to check if the fields were changed. The listener can add validation errors to your fields.
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormError;
use Acme\Bundle\Entity\Appointment;
class AppointmentType extends AbstractType
{
private $originalAppointment;
public function __construct(Appointment $original)
{
// save the original entity
$this->originalAppointment = clone $original;
}
// ...
public function buildForm(FormBuilderInterface $builder, array $options)
{
// define your fields
$builder->addEventListener(FormEvents::POST_SUBMIT, [$this, 'dateCheckListener']);
}
public function dateCheckListener(FormEvent $event)
{
$appointment = $event->getData();
$form = $event->getForm();
// if no appointments exist, we can skip the check
if (empty($appointment) || empty($this->originalAppointment)) {
return;
}
if ($appointment->getDate() !== $this->originalAppointment->getDate()) {
// the dates changed, you can call your validator here
if ('dates are not valid') {
$form->get('date')->addError(new FormError('We have a problem.'));
}
}
}
}
In your controller, you can create this formType with the original appointment:
$appointment = $this->getYourAppointmentSomehow();
$form = $this->createForm(new AppointmentType($appointment), $appointment);
Maybe you will find this article useful, to check which property is changed. Everything is possible in symfony. You might end up writing entity listeners, listener resolvers and so on. Things can get ultra advanced.
http://docs.doctrine-project.org/en/latest/reference/change-tracking-policies.html
Pay attention to the setter method:
public function setData($data)
{
if ($data != $this->data) {
$this->_onPropertyChanged('data', $this->data, $data);
$this->data = $data;
}
}
Do you see the trick?:)
I would also use !== operator to also check variable type.
You can also simplify things. You dont need to call _onPropertyChanged, but call the function, which will set a property 'dateChanged' to true. Then use method:
public function getGroupSequence()
{
if($this->dateChanged)
{
return ['date_check'];
}
else
{
return false;
}
}
And also tell your class that it implements GroupSequenceProviderInterface.
You can then use the validation group in your validation.yml for example.
maybe you want to try it with a preUpdate-Listener instead of a custom validation constraint?
Section 10.5.4 in the doctrine documentation gives an example of a validation listener "ValidCreditCardListener".
i know this will not work for automagic form validation, but i think it's the fastest way atm.
edit:
another option could be to use #UniqueEntiy constraint for the date field of your Appointment class. this will not break form validation but will cause an additional database query (as far as i know)

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)