ZF3 Doctrine Object provided to Escape helper, but flags do not allow recursion - zend-framework

In my specialisme entity i want to join al column and display rows from specialisme with the joined column, but i get error: Object provided to Escape helper, but flags do not allow recursion
In specialisme entity:
/**
* #ORM\OneToOne(targetEntity="User\Entity\User")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $fullname;
//...
/**
* Returns fullname.
* #return string
*/
public function getFullName()
{
return $this->fullname;
}
In controller:
public function indexAction()
{
//Array met alle user samenstellen
$users = $this->entityManager->getRepository(Specialisme::class)->findBy([], ['id'=>'ASC']);
//Users doorgeven aan view model
return new ViewModel([
'users' => $users
]);
return new ViewModel();
}
View:
<tr>
<th>Naam</th>
<th>Specialisme</th>
<th>Sub-specialisme</th>
</tr>
<?php foreach ($users as $user): ?>
<tr>
<td>f</td>
<td><?= $this->escapeHtml($user->getId()); ?></td>
<td><?= $this->escapeHtml($user->getFullName()); ?></td>
</tr>
<?php endforeach; ?>

It gives back the object,so i have to use the method of the referencing object:
$user->getBeschikbaarheid()->getOpZoekNaar());

Related

How can i create a relation beetwen two models and pass the model info on to the view through the controller?

My Student Model
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function fathers()
{
return $this->belongsTo('App\Models\Father');
}
My StudentController
/**
* Display the specified resource.
*
* #param ManageStudentRequest $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show(ManageStudentRequest $request, $id)
{
$student = Student::with('fathers')->find($id);
return view('students.show')->withStudent($student);
}
And my Blade View
<tr>
<th>NOMBRE</th>
<td>{{ $student->father->first_name }} {{ $student->father->last_name }}</td>
</tr>
The thing is i get this mistake:
Trying to get property of non-object (View: C:\laragon\www\App\resources\views\students\partials\show\show-overview.blade.php) (View: C:\laragon\www\App\resources\views\students\partials\show\show-overview.blade.php)
Im in desperate need for help, anything is useful, tyvm.
You should setup your structure to have a many to many relationship between students and fathers if that's the logic you want, so:
public function fathers()
{
return $this->belongsToMany('App\Models\Father');
//Also define the inverse relationship on the Father model.
}
Now assuming you've done that then:
On this query $student = Student::with('fathers')->find($id); just append first() so it looks like this:
$student = Student::with('fathers')->find($id)->first();
Then in your view you can access them like this:
<td>{{ $student->father->first_name }} {{ $student->father->last_name }}</td>

How do I store the relation between models in db? - Laravel

I have an employees table and a roles table. On the from to create an employee I also wish to assign a role. However my code stores the data with NULL on the foreign key in employees table. How do I make it store the relation?
Employees model.php
class employees extends Model
{
protected $fillable = [
'first_name',
'surname',
];
public function Roles()
{
return $this->belongsTo('App\Roles');
}
Roles model.php
class Roles extends Model
{
protected $fillable = [
'role_name',
];
public function Employees()
{
return $this->hasMany('App\Employees');
}
}`
Controller to create employee
public function store(EmployeesRequest $request)
{
$employee = Employees::find($request);
Employees::create($request->all());
Roles::create($request->all());
$employee->roles()->save($roles);
return redirect()->route('employees.index')->with('message','Employee has been added');
}
On the form I have first_name, surname and role_name. These are saved but with NULL on the role_id column in my employees table? Tried reading the laravel docs but struggling to use ->save method
Current error it is returning is Call to a member function roles() on null
You have to make the role_id fillable in your Employee Model:
protected $fillable = [
'role_id',
'first_name',
'surname',
];
In your Controller:
You need use App\Roles;
public function create()
{
$role = Role::lists('role_name', 'id');
return view('roles.create', compact('role'));
}
public function store(EmployeesRequest $request)
{
Employees::create($request->all());
return redirect()->route('employees.index')->with('message','Employee has been added');
}
Form:
<div class="form-group">
{!! Form::label('role_id', 'Role:') !!}
{!! Form::select('role_id', $role, null, ['class' => 'form-control']) !!}
</div>
HTML-Form:
Try something like this, I hope it works its not tested
<label>Role</label>
<select name="role_id">
#foreach($roles as $role)
<option value="{{ $role->id }}">{{ $role->role_name }}</option>
#endforeach
</select
In your Controller:
public function create()
{
$roles = Role::all();
return view('roles.create', compact('roles'));
}

Get customer data from id - magento2

how can we get the customer data from id not from customer session in Magento2.
Kindly let me know.
You can get all customer data from customer id in Magento 2. Here is the code snippet
<?php
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$customerFactory = $objectManager->get('\Magento\Customer\Model\CustomerFactory')-
>create();
$customerId = 1;
$customer = $customerFactory->load($customerId);
//fetch whole customer information
echo "<pre>";
print_r($customer->getData());
//fetch specific information
echo $customer->getEmail();
echo $customer->getFirstName();
echo $customer->getLastName();
You can also get customer billing address and shipping address from customer id. Full post is in this link
For the demonstrated purpose I have used Objectmanager. One should always use constructor method.
Load the customer by using the api factory. This is the correct way.
<?php
namespace Yourcompany\Customer\Helper {
/**
* Eav data helper
*/
class Data extends \Magento\Framework\App\Helper\AbstractHelper
{
protected $customerRepository;
public function __construct(
\Magento\Customer\Api\CustomerRepositoryInterfaceFactory $customerRepositoryFactory) {
$this->customerRepository = $customerRepositoryFactory->create();
}
public function LoadCustomerById($customerId) {
$cst = $this->customerRepository->getById($customerId);
return $cst;
}
}
?>
Here is the code snippet to get customer data by using id programmatically in magento 2 version
use \Magento\Framework\App\Bootstrap;
include('app/bootstrap.php');
$bootstrap = Bootstrap::create(BP, $_SERVER);
$objectManager = $bootstrap->getObjectManager();
$url = \Magento\Framework\App\ObjectManager::getInstance();
$storeManager = $url->get('\Magento\Store\Model\StoreManagerInterface');
$state = $objectManager->get('\Magento\Framework\App\State');
$state->setAreaCode('frontend');
$websiteId = $storeManager->getWebsite()->getWebsiteId();
// Get Store ID
$store = $storeManager->getStore();
$storeId = $store->getStoreId();
$customerFactory = $objectManager->get('\Magento\Customer\Model\CustomerFactory');
$customer=$customerFactory->create();
$customer->setWebsiteId($websiteId);
//$customer->loadByEmail('example#gmail.com');// load customer by email address
//echo $customer->getEntityId();
$customer->load('1');// load customer by using ID
$data= $customer->getData();
print_r($data);
You can get customer data by id by following way
namespace Vendor\Module\Block\Index;
class Index extends \Magento\Framework\View\Element\Template
{
protected $_customer;
public function __construct(
\Magento\Customer\Model\Customer $customer,
\Magento\Backend\Block\Template\Context $context
)
{
$this->_customer = $customer;
parent::__construct($context);
}
public function getCustomer()
{
$customerId = '3'; //You customer ID
$customer = $this->_customer->getCollection()->addAttributeToFilter('entity_id', array('eq' => '3'));
print_r($customer->getData());//Customer data by customer ID
}
}
It is recommended to use dependency injection instead of using object manager.
Create block like
namespace Lapisbard\General\Block;
use Magento\Customer\Model\Session;
class CustomerAccount extends \Magento\Framework\View\Element\Template {
public function __construct(
Session $customerSession,
\Magento\Framework\View\Element\Template\Context $context
)
{
parent::__construct($context);
$this->_customerSession = $customerSession;
}
public function getCustomerName(){
$this->_customerSession->getCustomer()->getName();
}
}
And use it in your template like
<?php echo $block->getCustomerName(); ?>
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$customer = $objectManager->create('Magento\Customer\Model\Customer')->load($customerId);
$xxx = $customer->getData('xxx');
$customer = $this->objectManager->create('Magento\Customer\Model\Customer')->load(1);
Instead of objectManager you should use dependency injection.
This is the old Ans Magento updated this
You can get customer data from following method also more options are available
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$customer = $objectManager->create('Magento\Customer\Model\Customer')->load(1);
Also you can use Magento\Customer\Model\Customer for blocks using dependency injection.The main benefits of using object manager is it can be used in phtml.
I am facing same problem when Cache enable I am not able to get customer session.But I find below solution
/**
* #var \Magento\Customer\Model\Session
*/
protected $_customerSession;
public function __construct(Template\Context $context,
\Magento\Framework\App\Request\Http $request,
\Magento\Customer\Api\CustomerRepositoryInterface $customerRepository,
\Magento\Customer\Model\SessionFactory $customerSession
)
{
$this->request = $request;
$this->customerRepository = $customerRepository;
$this->_customerSession = $customerSession;
parent::__construct($context);
}
public function getCustomerId(){
$customer = $this->_customerSession->create();
var_dump($customer->getCustomer()->getId());
}
Use above code in block It is working even cache is enable.
Second Solution:
Add cacheable="false" in your xml
<referenceContainer name="content">
<block class="Vendor\Modulename\Block\Customer" name="customer.session.data" template="Vendor_Modulename::customertab.phtml" cacheable="false" />
</referenceContainer>
Add below code in block:
/**
* #var \Magento\Customer\Model\Session
*/
protected $_customerSession;
/**
* Construct
*
* #param \Magento\Framework\View\Element\Template\Context $context
*/
public function __construct(Template\Context $context,
\Magento\Framework\App\Request\Http $request,
\Magento\Customer\Api\CustomerRepositoryInterface $customerRepository,
\Magento\Customer\Model\Session $customerSession
)
{
$this->request = $request;
$this->customerRepository = $customerRepository;
$this->_customerSession = $customerSession;
parent::__construct($context);
}
public function getOrderData(){
$customerId = $this->_customerSession->getCustomerId();
var_dump($this->_customerSession->getCustomer());
}
Get Customer Details In Magento2 By Id
use Magento\Customer\Model\CustomerFactory;
class CustomClass {
/**
* #var CustomerFactory
*/
private $customerFactory;
public function __construct(
CustomerFactory $customerFactory,
) {
$this->customerFactory = $customerFactory;
}
public function getCustomerDetails() {
$customerId=6;
// $customerId =$this->getCustomerIdByEmail();
// $customerId =$this->getCustomerIdByMobile();
$loadData =$this->customerFactory->create()->load($customerId);
$allData = $loadData->getData());
print_r($allData);
}
}
To Get The Customer ID By Email
public function getCustomerIdByEmail() {
$customerId = $this->customerFactory->create()->getCollection()
->addFieldToFilter('email', $email)
->getFirstItem()->getId();
}
To Get The Customer ID By Mobile Number
public function getCustomerIdByMobile() {
$customerId = $this->customerFactory->create()->getCollection()
->addFieldToFilter('mobile_number', $mobile_number)
->getFirstItem()->getId();
}

How to edit nested collections in MVC5?

I have a EF-model which contains a "key" and a "value". The value-table contains a FK to the key. In the EF-model it looks like this:
public partial class dict_key
{
public dict_key()
{
this.dict_value = new HashSet<dict_value>();
}
public int id { get; set; }
public string name { get; set; }
...
public virtual ICollection<dict_value> dict_value { get; set; } //dict_value contains a string "value"
}
My controller is passing the information for editing like this:
// GET: Keys/Texts/5
[Authorize]
public async Task<ActionResult> Texts(int? id)
{
var key = await db.dict_key
.Include(x => x.dict_value)
.Where(x => x.id.Equals(id.Value))
.FirstOrDefaultAsync();
return View(key);
// Debugging 'key' shows that dict_value has 3 correct values.
}
This gets passed to my View which shows the dict_value's correct:
#model Dict.Models.dict_key
#using (Html.BeginForm())
{
<div>Key: #Model.name </div>
<table class="table">
<tr>
<th>Language</th>
<th>Text</th>
</tr>
#for (var i = 0; i < Model.dict_value.Count(); i++)
{
<tr>
<td> #Model.dict_value.ElementAt(i).dict_lang.name_en </td>
<td> #Html.EditorFor(x => x.dict_value.ElementAt(i).value) </td>
</tr>
}
<div class="form-group">
<input type="submit" value="Save" />
</div>
</table>
}
When submitting my changes back to the controller...
[HttpPost]
public async Task<ActionResult> Texts(dict_key dict_key)
{
if (ModelState.IsValid)
{
//Also tried: db.Entry(dict_key).State = EntityState.Modified;
db.Entry(dict_key.dict_value).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("Texts");
}
return View(dict_key);
}
..then my "dict_key" is totally different from the object I passed to my edit-view. The passed object contained the collection of dict_value's and the "returned" and edited object returns with the proper key object, but with an empty dict_value collection.
I try to avoid using a userdefined model or the viewbag to do all of that stuff manually. What is the best practise solution for this?
Collection.ElementAt doesn't generate a proper field name in Razor. You need a List. Here you should use a view model instead of your entity directly and simply make your dict_value collection a List<dict_value> there.
Alternatively, you can create an editor template for dict_value and then in your view just do:
#Html.EditorFor(m => m.dict_value)
Where dict_value there is your entire collection. Razor will render an instance of the editor template for each member of the collection and properly index everything.

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 }