Livewire Lifecycle Hooks self update to upper - laravel-livewire

Hi is it possible to make live self update to upper form field payment?
because that works if set another field of form not the same.
public function updatingpayment($value)
{
$this->upper($value);
}
public function upper($value){
$process = strtoupper($value);
$this->payment=$process;
}

You still need to reference the field from the lifecycle method, Livewire doesn't know your intention.
public function updatedPayment($value)
{
$this->payment = strtoupper($value);
}

Related

Laravel Livewire Life hook livewire, v.2.11 updated/updating

When it try trigger to updated life hook when property is changed/updated not work
example
...
public function updatedName($name){
dd($this->name);
}
and I find this message from livewire doc.
Please note that mutating a property directly inside a Livewire component class doesn't trigger any of the updating/updated hooks.
Please. do someone can explain in detail this message from https://laravel-livewire.com/docs/2.x/lifecycle-hooks meaning and what should be done instead
The warning means that the Lifecycle Hooks are not called when you update a property inside the PHP component class.
An example usage is to catch when a user updates a property via the wire:model attribute.
class HelloWorld extends Component
{
public $foo;
public function updatedFoo($value)
{
//
}
public function mount()
{
$this->foo = "New Value";
// updatedFoo will NOT be called
}
}
<input type="text" wire:model="foo" />
<!-- Entering text into this field will cause the hook to be called -->
try this
public $name;
public function updatedName($value)
{
// if you want get value
dd($value);
// if you want change name to new value
$this->name = $value
}

Custom form field in views

I'm trying to create a custom field for a view in Drupal 8 which allows to perform an action without changing the page (link). I guess I have to create a form inside that custom field but I do not know how to achieve it.
Any idea on how to do it or other alternative without redirecting to a route?
The view will be a list of custom entities and I need a button for each of the lines.
Thanks in advance!
Finally I solved it by following this steps:
I created a view custom field (generate:plugin:views:field with
drupal console)
I created a form (generate:form)
Then, in the view custom field render function return the form:
$form = \Drupal::formBuilder()->getForm('Drupal\test_module\Form\TestForm', $values->_entity->ID());
return $form;
It's important to notice that an incremental (dynamic) formId is needed for things to work properly. I did that by creating a static variable and a __construct() method as follows:
protected static $instanceId;
public function getFormId() {
return 'my_form_id_' . self::$instanceId;
}
public function __construct(){
if (empty(self::$instanceId)) {
self::$instanceId = 1;
}
else {
self::$instanceId++;
}
}

Drupal 8 subscribe to an event from inside block

I am currently trying to wrap my head around Drupal 8 module development best practices. All I'm trying to do is to have a simple form Demoform on a page where a user can input an email address. When the form gets submitted I'd like to dispatch an event demo_form.save. Also I need a block that then displays the user's email address within the block (let's say sidebar second). I have already implemented an EventSubscriber before as a test, so the event gets properly dispatched etc. and I also subscribed to the event (but how to get the information inside a block) Now my question: what's the best practice for this workflow:
File DemoForm.php
class DemoForm extends ConfigFormBase {
...
$event = $dispatcher->dispatch('demo_form.save', $e);
...
}
File DemoEventSubscriber.php
class DemoEventSubscriber implements EventSubscriberInterface {
static function getSubscribedEvents() {
$events['demo_form.save'][] = array('onConfigSave', 0);
return $events;
}
public function onConfigSave($event) {
...
}
}
This works and I can access the input from the form inside the DemoEventSubscriber class and do whatever I want with it.
But now I'd like to display the email address inside the block markup. How should this best be done ?
File DemoBlock.php
class DemoBlock extends BlockBase {
public function build() {
// here return markup with email address from form
}
}
How do I combine the eventsubscriber and the block markup ? Can Blockbase itself implement the EventSubscriberInterface and be independent from DemoEventSubscriber.php ? Or do I need to register a service that transmits the form data and then access the service within the block's build() function ? Or is there another way I am missing ?
Thanks for any input.
I am not sure what you need the event for, but to dispatch the event, use the code you have already displayed in your submitForm() function of the DemoForm class.
Because you are using ConfigFormBase, I assume that you want to store the submitted e-mail address in config, use code like from the config form documentation:
/**
* {#inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// Retrieve the configuration
$this->config('mymodule.settings')
// Set the submitted configuration setting
->set('email', $form_state->getValue('email'))
->save();
// Assuming you have injected the dispatcher.
$event = $this->dispatcher->dispatch('demo_form.save', $e);
parent::submitForm($form, $form_state);
}
Within you block, you can then access the configuration for example with the static wrapper or inject the service Simple Configuration API
$config = \Drupal::config('mymodule.settings');
$message = $config->get('email');
Note that with this you can always set only one e-mail address. I don't know if that was your purpose. If you want to collect multiple e-mails then you should store them in the database and not in config.

Recomputing entity changeset in onFlush listener

Consider the following schema:
[Work]
id
tags ManyToMany(targetEntity="Tag", inversedBy="works", cascade={"persist"})
[Tag]
id
works_count
works ManyToMany(targetEntity="Work", mappedBy="tags")
works_count is a counter cache for Tag::works.
I have a onFlush listener on Work that checks if Work::tags has changed, and updates each of the tags' works_count.
public function onFlush(OnFlushEventArgs $args)
{
foreach ($uow->getScheduledEntityUpdates() as $work) {
$changedTags = /* update relevant tags and return all the changed ones */
$metadata = $em->getClassMetadata('Acme\Entity\Tag');
foreach ($changedTags as $tag) {
$uow->recomputeSingleEntityChangeSet($metadata, $tag);
}
}
}
Now if I read the changesets of the updated tags, the changes of works_count appears correctly, but they don't get updated in the database..
If I replace recomputeSingleEntityChangeSet() with computeChangeSet() then everything works as expected and the DB is updated, but computeChangeSet() has an #internal Don't call from the outside. annotation on it, so I'm not sure what the consequences are..
Every source on the internet says to use recomputeSingleEntityChangeSet so why doesn't it work in this case?
P.S
The tags are managed by the EntityManager ($em->contains($tag) returns true)
This problem was related with a bug in UnitOfWork and finally it's fixed with the release of Doctrine ORM 2.4.3 on September 11, 2014. See DDC-2996 for details.
It seems that Doctrine 2.2 can merge change sets or generate new change sets, but it needs to know which. If you get it wrong, it will either replace your existing change sets or do nothing at all. I'd be very interested to know if there is a better option than this, or if this is even right.
if($uow->getEntityChangeSet($entity)) {
/** If the entity has pending changes, we need to recompute/merge. */
$uow->recomputeSingleEntityChangeSet($meta, $contact);
} else {
/** If there are no changes, we compute from scratch? */
$uow->computeChangeSet($meta, $entity);
}
In doctrine 2.4.1, use recomputeSingleEntityChangeSet only if you are changing tag in the event listener AND UOW contain tag ChangeSet (Change that happen outside of the event listener). Basically recomputeSingleEntityChangeSet is a function to merge ChangeSet for an entity.
Doc from the function
The passed entity must be a managed entity. If the entity already has a change set because this method is invoked during a commit cycle then the change sets are added whereby changes detected in this method prevail.
NOTE: You need to make sure UOW already have ChangeSet for the entity, otherwise it will not merge.
For future readers, at all cost try to avoid the listeners. Those are hardly testable, your domain should not rely on magic. Consider OP's test case how to achieve the same without Doctrine events:
Work class:
public function addTag(Tag $tag): void
{
if (!$this->tags->contains($tag)) {
$this->tags->add($tag);
$tag->addWork($this);
}
}
Tag class:
public function addWork(Work $work): void
{
if (!$this->works->contains($work)) {
$work->addTag($this);
$this->works->add($work);
$this->worksCount = count($this->works);
}
}
TagTest class:
public function testItUpdatesWorksCountWhenWorkIsAdded()
{
$tag = new Tag();
$tag->addWork(new Work());
$tag->addWork(new Work());
$this->assertSame(2, $tag->getWorkCount());
}
public function testItDoesNotUpdateWorksCountIfWorkIsAlreadyInCollection()
{
$tag = new Tag();
$work = new Work();
$tag->addWork($work);
$tag->addWork($work);
$this->assertSame(1, $tag->getWorkCount());
}

Doctrine 2 self-referencing entity won't return the parent id

I've set up a self-referencing entity per the manual here:
http://www.google.com/url?sa=D&q=http://www.doctrine-project.org/docs/orm/2.0/en/reference/association-mapping.html%23one-to-many-self-referencing
My class is Page (instead of Category, like in the docs). In my entity
class I have a toArray() method that I've implemented that will give
me back the values of my member variables. For those fields that are
associations, I've made sure to grab the associated class object then
grab the id. I'm doing this to populate a form. Here is the code from
my toArray() method in my Page entity as well as my PageService
function to grab a Page object and my Page Controller code that calls
toArray() to populate my form.
http://pastie.org/1686419
As I say in the code comments, when the toArray() method is called in
the Page Controller, all values get populated except for parent id.
page_type is also a ManyToOne association and it gets populated no
problem. Explicitly grabbing the parent id from the Page object
outside of the toArray() method (in the Page Controller) does return
the parent id value. (See code.)
As a side note, I'm using __get() and __set() in my Page entity instead of full blown getters/setters.
I think it is because you are getting caught out by proxies. When you have an association in Doctrine 2, the related objects are not returned directly as objects, but as subclasses which do not fill their properties until a method is called (because of lazy loading to save database queries).
Since you are calling the property directly (with $this->parent->id) without invoking any method the object properties are all empty.
This page http://www.doctrine-project.org/docs/orm/2.0/en/tutorials/getting-started-xml-edition.html#a-first-prototype has a warning about this type of thing in the warning box. Although yours isn't a public property, you are accessing as though it were because that object is of the same class and the same problem is occuring.
Not sure of exactly what is causing your described behavior, but you're probably better anyway to have your toArray() method call getters/setters rather than having toArray() operate directly on the class properties. This will give you consistency so that if you implement custom getters for certain properties, you'll always get back the same result from toArray() and the getter.
A rough example:
<?php
/** #Entity */
class MyEntity {
// ....
/** #Column */
protected $foo;
public function setFoo($val)
{
$this->foo = $val;
}
public function getFoo()
{
return 'hello ' . $this->foo;
}
public function toArray()
{
$fields = array('foo');
$values = array();
foreach($fields as $field) {
$method = 'get' . ucfirst($field);
if (is_callable(array($this, $method)) {
$fields[$field] = $this->$method();
} else {
$fields[$field] = $this->$field;
}
}
return $fields;
}
}
Now you get the same result:
<?php
$e = new MyEntity;
$e->setFoo('world');
$e->getFoo(); // returns 'hello world'
$e->toArray(); // returns array('foo' => 'hello world')