Laravel one to many relationship save method empty attributes - forms

I am trying to save a relationship with the Laravel save method:
public function storeContact(Request $request)
{
$user = User::firstOrNew(['email' => $request->input('email')]);
$user->save();
$message = new App\Message([
'message' => $request->input('remarks')
]);
$user->message()->save($message);
}
var_dump($request->all) confirms both fields are available in the request.
All relations work. hasOne, belongsTo are configured in the models. The relation is saved like expected (but message field is empty)
When I var_dump($message), there are no attributes in the collection.
I already tried fillable and guarded on the models without any effect. These should not be necessary for the save method though because this uses a full Eloquent model instance.
What am I missing here??

I think I found the culprit.
When I use a __construct on a model it fails. When I instantiate a model with a __construct no variables are passes as attributes. Even if the __construct is empty.
Test with __construct method
class Message extends Model
{
protected $connection = 'system';
public function __construct()
{
}
// ...
}
$message = new App\Message(['remarks' => 'Test remarks']);
var_dump(message) // does NOT contain attributes!
Test2 without __construct method
class Message extends Model
{
protected $connection = 'system';
// ...
}
$message = new App\Message(['remarks' => 'Test remarks']);
var_dump(message) // does contain attributes!
This looks like a bug in Laravel to me.

Related

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();
}

capturing the login event in zendframework 2

I want to capture the loggin event in zendframework2 and then update the database when the user last logged in.
i am aware that if i do the following in the onBootstrap(MVCEvent $e) of my module i will be able to capture the event etc:
$eventManager = $e->getApplication()->getEventManager();
$em = $eventManager->getSharedManager();
$em->attach(
'ZfcUser\Authentication\Adapter\AdapterChain',
'authenticate',
function($e)
{
$id = $e->getIdentity();
}
);
this will give me the Id of the user. however, the confusion is how i can then update my database from the bootstrap. i mean, i dont have access to the entity manager in my bootstrap and i am not sure how to transport it there. the entity manager is held in the service config file.
i.e
getServiceConfig()
'Members\Model\WorkerTable' => function($sm) {
$db = $sm->get('doctrine.entitymanager.orm_default');
$table = new Model\MemberTable($db);
return $table;
},
.
with the above settings i am able to access the entity manager in my MemberTable class
so, a simple solution would be to transfer the loggin event manager to my
** MemberTable class** where i would use my entity manager to update the database.
issue, i am not sure how to set this up:
$eventManager = $e->getApplication()->getEventManager();
$em = $eventManager->getSharedManager();
i mean, i dont know how to get the variable $e into the MemberTable class so that i can access the eventManger and the sharedManager.
in summary; the issues are twofold.
how do i get the entity manager into the bootstrap function
alternatively
how do i get the eventManager and shared eventmanager into a normal class so that i can call the eventmanger in a class that already contains the entity manager
Well, all you have to do is to retrieve the service manager this way:
$serviceManager = $e->getApplication()->getServiceManager();
and then get your entity manager like this:
$entityManager = $serviceManager->get('Members\Model\WorkerTable');
Does it solve your problem?
The answer to the second question
To bring a variable into the closure from outside you can use "use" operator like so:
function() use ($myVar){
// some code
}
So, in your case I would do:
$eventManager = $e->getApplication()->getEventManager();
$em = $eventManager->getSharedManager();
$em->attach(
'ZfcUser\Authentication\Adapter\AdapterChain',
'authenticate',
function($e) use ($entityManager){
$id = $e->getIdentity();
}
);
If you are planning to have a lot of code inside your closure I would suggest to put it into a separate class and make it invokable. For instance,
class YourClosureCode
{
private $entityManager;
public function __construct($eventManager)
{
$this->eventManager = $eventManager;
}
public function __invoke(EventInterface $e)
{
// put your closure code here
}
}
Then a slight modification here:
$eventManager = $e->getApplication()->getEventManager();
$em = $eventManager->getSharedManager();
$em->attach(
'ZfcUser\Authentication\Adapter\AdapterChain',
'authenticate',
new YourClosureCode($entityManager);
);

Symfony2: how to get the Type that a form is constructed from

I'm trying to dynamically generate my forms based on the user's permissions for that I have created a extension which adds listeners to forms and filters their fields accordingly.this works just fine However I'm having trouble with getting the typeName (returned from the getName method for classes which implement the FormTypeInterface) of each field (which is FormInterface).I've tried FormInterface::getName but that returns the field name that is given to the builder e.g: $builder->add('fieldName',new FooType()) when I call getName on a FormInterface that is constructed like this I get "fieldName".What I want is the returned value from FooType::getName.How can I do that?I have also checked FormInterface->getConfig->getName() but that also gave the same same Result.the code for the listener:
class FooListener implements EventSubscriberInterface{
public static function getSubscribedEvents()
{
//set low priority so it's run late
return array(
FormEvents::PRE_SET_DATA => array('removeForbiddenFields', -50),
);
}
public function removeForbiddenFields(FormEvent $event){
$form = $event->getForm();
$formName = $form->getName();/*what I want for this is to return the name of the
type of the form.e.g: for the field that is construced with the code below
it must return FooType::getName*/
$fields = $form->all();
if($fields){
$this->removeForbiddenFormFields($form, $formName, $fields);
}
}
}
class barType extends AbstractType{
public function buildForm(FormBuilderInterface $builder, array $options){
$builder->add('fieldName',new FooType());
}
....
}
For those of you using Symfony 3 this can now be done with:
$formClass = $form->getConfig()->getType()->getInnerType();
$formClass will be a stdClass representation of the class itself (not the instance of it though), and you can use get_class($formClass) to get a string for its FQCN, e.g. "App\Form\Type\SillyFormType".
I've not tested this on Symfony 4, though it'll likely be the same.
I found the answer.
$form->getConfig()->getType()->getName();
this will return a name returned from the FooType::getName through a ResolvedTypeDataCollectorProxy class.
From Symfony > 2.8 getName() is deprecated and removed.
You can now use:
$form->get('fieldName')->getConfig()->getInnerType()
To get specific FieldName Type.
not sure this is what you are looking for, this goes in the form FormName
public function __construct($permissions = null) {
$this->permissions = $permissions;
}
and this is how you create the form, while in buildForm you can use an if or some other logic
$myForm = $this->createForm(new FormName($user->getPermissions()));

CUploadedFile::getInstance Always Returns Null on Uploaded File

I have built a form in YII and I need to process an uploaded file. I followed this guide, but I've stumbled upon an issue. CUploadedFile::getInstance always returns null.
Here's what I use. My model:
class AdditionalFieldFile extends CFormModel {
public $uploadedFile;
/**
* #return array validation rules for model attributes.
*/
public function rules() {
return array(
//note you wont need a safe rule here
array('uploadedFile', 'file', 'allowEmpty' => true, 'types' => 'zip,doc,xls,ppt,jpg,gif,png,txt,docx,pptx,xlsx,pdf,csv,bmp'),
);
}
}
And handling the uploaded file in the controller on form submit:
$model = new AdditionalFieldFile();
$model->uploadedFile = CUploadedFile::getInstance($model, 'field_'.$type_field.'['.$id_common.']');
And after that $model->uploadedFile is null for some reason.
Note that $type_field and $id_common come dynamically.
Also, the form has 'enctype'=>'multipart/form-data' so this is not the cause.
Ok, a self-answer follows.
It turns out that I had to use the active file field in the view, using an instance of the class that extends CFormModel as a model.
Solution:
CHtml::activeFileField(new AdditionalFieldFile(), 'field_'.$type_field.'['.$id_common.']');

How to write a custom row class (extends Zend_Db_Table_Row) for a Db_Table class in Zend Framework

I have separate db_table classes for books, book_sections and users (system end users). in book table has columns for book_title, section_id(book_section) , data_entered_user_id(who entered book info).
go to this url to see the image(I'm not allow to post images bacause I'm new to stackoverflow)
img685.imageshack.us/img685/9978/70932283.png
in the backend of the system I added a form to edit existing book (get book id from GET param and fill the relevant data to the form). form has elements for book_title, book_section and data_entered_user.
to get exciting book data to "edit book form" I join book_section and user tables with book table to get book_section_name and username(of data_entered_user: read only- display on side bar)
go to this url to see the image(I'm not allow to post images bacause I'm new to stackoverflow)
img155.imageshack.us/img155/2947/66239915.jpg
In class App_Model_Book extends Zend_Db_Table_Abstract
public function getBookData($id){
$select = $this->select();
$select->setIntegrityCheck(false);
$select->from('book', array('id','section_id','data_entered_user_id',...));
$select->joinInner('section','book.section_id = section.id',array('section_name' =>'section.name' ));
$select->joinInner(array('date_entered_user' => 'user'),'book.date_entered_user_id = date_entered_user.id',array('date_entered_user_name' =>'date_entered_user.user_name' ));
$select->where("book.id = ?",$id);
return $this->fetchRow($select);
}
public function updateBookData($id,$title,$section_id,...)
{
$existingRow = $this->fetchRow($this->select()->where('id=?',$id));
$existingRow->title = $title;
$existingRow->section_id = $section_id;
//....
$existingRow->save();
}
In Admin_BookController -> editAction()
$editForm = new Admin_Form_EditBook();
$id = $this->_getParam('id', false);
$bookTable = new App_Model_Book();
$book_data = $bookTable ->getBookData($id);
//set values on form to print on form when edit book
$editForm->book_title->setValue($book_data->title);
$editForm->book_section->setValue($book_data->section_name);
//........
//If form data valid
if($this->getRequest()->isPost() && $editForm->isValid($_POST)){
$bookTable = new App_Model_Book();
$bookTable ->updateBookData(
$id,
//get data from submitted form
$editForm->getValue('title'),
//....
);
when editing an exsiting book
get data from getBookData() method on App_Model_Book class
If form data is valid after submiting edited data, save data with updateBookData() method on App_Model_Book class
but I saw that if I created a custom
Db_Table_Row(extends Zend_Db_Table_Row)
class for book table with
book_section_name and
data_entered_user_name I can use it
for get existing book data and save it
after editing book data without
creating new Book(db_table) class and without calling updateBookData() to save updated data.But I don't know which code I should write on custom
Db_Table_Row(extends Zend_Db_Table_Row)
class.
I think you can understand my problem, in simple
how to write a custom db_table_row class to create a custom row with data
form 2 joined tables for a perticular db_table class ?
I'm new to zend framewok and to stackoverflow. forgive me if you confused with my first question.
Thanks again.
1) at your db_table class create field which contain row class, for example:
protected $_rowClass = 'App_Model_Db_Books_Row';
and add reference map for parent tables:
protected $_referenceMap = array(
'Section' => array(
'columns' => 'sectionId',
'refTableClass' => 'App_Model_Db_Sections',
'refColumns' => 'id'
),
'User' => array(
'columns' => 'userId',
'refTableClass' => 'App_Model_Db_Users',
'refColumns' => 'id'
)
);
2) at row class you must define variables for parent tables:
protected $section;
protected $user;
In such cases i create method called "load":
public function load()
{
$this->section = $this->findParentRow('App_Model_Db_Sections');
$this->user = $this->findParentRow('App_Model_Db_Users');
}
And in constructor i call this method:
public function __construct(array $config = array())
{
parent::__construct($config);
$this->load();
}
As a result after:
$book_data = $bookTable ->getBookData($id);
you can access data from reference table, for example:
$book_data->section->name = "Book Section";
$book_data->section->save();