Livewire how to revert input changes? - laravel-livewire

let say I got $foo in my component and I bind this property to an input wire:model="foo.{{ $index }}.column", I will do some checking everytime when user make changes on this input, how can I stop the update process or revert the input back to previous value? Method below wont work because after updating method it will still go to updated method, but I cant get previous value in updated method
public $foo = [];
public function updatingFoo($value, $key)
{
//checking
if(true) {
$previousValue = Arr::get($this->foo, $key);
Arr::set($this->foo, $key, $previousValue);
}
}

Related

In OpenCart3 how to prevent adding extra characters in $this->cart->add(...)?

I'm customizing OpenCart3. For some reasons I have to save contents of cart table in a session, then re-insert them back, but while adding session data using $this->cart->add(...) extra codes are added to options which I don't know how to prevent.
foreach($this->session->data['in_cart']['rows'] as $key => $row){
if ($row['store_id'] != $this->session->data['cart_store_id']) {
$this->cart->add($row['product_id'], $row['quantity'], $row['option'], $row['recurring_id'], $row['store_id']);
}
}
Originally options should be saved like:
{"90":["263"],"89":["260"]}
But they get saved as:
"{\"142\":[\"494\"],\"141\":[\"492\"]}"
Thanks for any kind help, but not down voting.
I fixed the problem by decoding the saved string into array, then adding it:
foreach($this->session->data['in_cart_total_products_all_stores']['rows'] as $key => $row){
if ($row['store_id'] != $this->session->data['cart_store_id']) {
$options = json_decode($row['option']);
$this->cart->add($row['product_id'], $row['quantity'], $options, $row['recurring_id'], $row['store_id']);
}
}

Test JSON-returning controller method without MissingViewError

I am testing a Controller method that has only a JSON view. My method runs as expected, but the test method only returns "MissingViewException". Is there a solution to avoiding this exception in the unit test (besides inserting an empty file at View/People/map_leads.ctp)?
PeopleController.php
public function mapLeads($territory_id = null) {
$leads = $this->Person->getPeople([
'territory_id' => $territory_id
]);
$this->set('leads', $leads);
}
AppController.php
public $components = ['RequestHandler'];
routes.php
Router::parseExtensions('json');
PeopleControllerTest.php
public function testMapLeads() {
$id = 40;
$result = $this->testAction('/people/mapLeads/' . $id, array('return' => 'vars'));
}
View/People/json/map_leads.ctp exists and is properly utilized by CakePHP; it is only the test that wants to see View/People/map_leads.ctp.
I checked at CakePHP: calling testAction to a json-returning method causes missing view exception reminding about adding RequestHandler to $components. This does not resolve the exception.
You aren't issuing a JSON request/accessing a JSON endpoint, as neither your request URL does contain the .json extension, nor does your request send an appropriate Accept header (I don't remember whether the latter is possible with the 2.x controller test case class at all).
Use the .json extension and you should be good.
$this->testAction('/people/mapLeads/' . $id . '.json', array('return' => 'vars'));
Write this code inside your action.
$this->autoLayout = false;
$this->autoRender = false;
$this->response->type('application/javascript');

Flow: Convert object to array for CSV export

I want to export my object "mitglied" to a .csv-file. My controller looks like that:
public function exportAction() {
// find all mitglieds
$records = $this->mitgliedRepository->findTennis();
// Set path for export-file
$csvPath = '/var/www/apps/flow/Packages/Application/ITOOP.Atc/Resources/Private/Export/test.csv';
$fp = fopen($csvPath, 'w');
foreach ($records as $lines) {
fputcsv($fp, $lines);
}
fclose($fp);
}
When I call the exportAction, I get a an error:
#1: Warning: fputcsv() expects parameter 2 to be array, object given in /var/www/apps/flow/Data/Temporary/Development/Cache/Code/Flow_Object_Classes/itoop_atc_Controller_MitgliedController.php line 494
line 494 is...
fputcsv($fp, $lines);
...so I think I have to convert the object "mitglied" to an array.
My the public function findTennis in my mitgliedRepository looks like that:
public function findTennis() {
$query = $this->createQuery();
$result = $query->matching($query->equals('abteilung', 'Tennis'))
->setOrderings(array('name' => \TYPO3\Flow\Persistence\QueryInterface::ORDER_ASCENDING))
->execute();
return $result;
}
I tried to set toArray(); in the repository like the that:
public function findTennis() {
$query = $this->createQuery();
$result = $query->matching($query->equals('abteilung', 'Tennis'))
->setOrderings(array('name' => \TYPO3\Flow\Persistence\QueryInterface::ORDER_ASCENDING))
->execute()
->toArray;
return $result;
}
But then I get the following error:
#1: Notice: Undefined property: TYPO3\Flow\Persistence\Doctrine\QueryResult::$toArray in /var/www/apps/flow/Data/Temporary/Development/Cache/Code/Flow_Object_Classes/itoop_atc_Domain_Repository_MitgliedRepository.php line 105
line 105 of course is
->toArray;
Does anybody know, how to convert an object to an array in flow?
With the following example the export works, so I think the (formatting of the) repository query is the problem.
public function exportAction() {
// Set path for export-file
$csvPath = '/var/www/apps/flow/Packages/Application/ITOOP.Atc/Resources/Private/Export/test.csv';
$test = array (
array('xxx', 'bbb', 'ccc', 'dddd'),
array('123', '456', '789'),
array('aaa', 'bbb')
);
$fp = fopen($csvPath, 'w');
foreach ($test as $lines) {
fputcsv($fp, $lines);
}
fclose($fp);
}
Please point me to the right direction. Thank you!
The error messages explained
#1: Warning: fputcsv() expects parameter 2 to be array, object given in /var/www/apps/flow/Data/Temporary/Development/Cache/Code/Flow_Object_Classes/itoop_atc_Controller_MitgliedController.php line 494
fputcsv expects it's 2nd parameter to be an array. That array will be written as a CSV line into single file, with each array element as column. When iterating over your $records variable, you get instances of your domain object class (so probably sth. like ITOOP\Atc\Domain\Model\Mitglied). That's undefined behaviour, thus the warning.
#1: Notice: Undefined property: TYPO3\Flow\Persistence\Doctrine\QueryResult::$toArray in /var/www/apps/flow/Data/Temporary/Development/Cache/Code/Flow_Object_Classes/itoop_atc_Domain_Repository_MitgliedRepository.php line 105
toArray is a function that is offered by Doctrine QueryResult class. Typically, Doctrine queries do not fetch all objects returned by the query, but return an iterator that fetches and maps entities on-demand. The toArray method fetches all records at once and returns an array instead of the iterator. Your error occurs, because you try to access toArray as a property, and not calling it as a method. The following code would be correct:
$result = $query->matching($query->equals('abteilung', 'Tennis'))
->setOrderings(array('name' => \TYPO3\Flow\Persistence\QueryInterface::ORDER_ASCENDING))
->execute()
->toArray(); // <- Mind the brackets!
However, this will not help you anything, because in your controller, you will still be iterating over a list of domain entities (foreach does not care if its iterating over an iterator or an array; that's actually the point of iterators in PHP).
Quick&Dirty solution
Convert your domain entities by hand in your controller. Only you can know how your CSV export should look like, so this cannot be automated. I'm thinking something like this:
foreach ($records as $record) {
$csvLine = [
$record->getFirstProperty(),
$record->getSecondProperty(),
// and so on...
];
fputcsv($fp, $csvLine);
}
Better solution
Rendering CSV data is not a concern that should be addressed in the controller. Basically, it should go into a view. You can implement a custom view class for handling the CSV output.
For that, you need to implement the \TYPO3\Flow\Mvc\View\ViewInterface. The easiest way to do this is to subclass \TYPO3\Flow\Mvc\View\AbstractView. Name your view class <PackageNamespace>\View\<Controller>\Action<Format> (so sth. like ITOOP\Atc\View\Mitglied\ExportCsv. Implement your CSV export logic in the view's render() method. Flow will pick up and use the view class automatically as soon as it's present.
Implementing custom views is explained in depth in this article -- it's in German though, although based on your class naming I suspect that won't be a problem ;).
I solved the problem with arbitrary DQL. As I mentioned I think the problem was that I didn't got an array as result by the query. But with the following query in my repository I do:
/**
* #Flow\Inject
* #var \Doctrine\Common\Persistence\ObjectManager
* inject Doctrine's EntityManager to execute arbitrary DQL
*/
protected $entityManager;
/**
* find mitglieder with Abteilung Tennis und return an array
*/
public function exportTennis() {
$query = $this->entityManager->createQuery("SELECT mitglied FROM \itoop\atc\Domain\Model\Mitglied mitglied WHERE mitglied.abteilung = 'Tennis'");
return $query->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);
}
The important part I think is getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);

Symfony2 : Handling error on a single controller

I made a controller to provide some webservices in JSON and i would like to provide some errors informations when Symfony throw an exception ( Error 500 ) , how can i write such a thing ?
The main purpose of the webservice is to update informations in Symfony DB provided by the caller in POST values.
in my controller i return response in JSON and i would like to handle Symfony exception ( like when the values provided or not fitting the schema designed ) to return details informations about errors .
i thought about making a test of every values but it would be a long time to write and not e easy code to read or using a try / catch system , but i think Symfony already provide such a function .
What do you think ?
Thx :)
I think you should use an EventListener to catch errors and return the proper response.
You can place it inside your SomethingBundle/EventListener folder and also you need to define a service in order to be loaded by Symfony.
More info: Event Listener
I hope I helped you, if you think I might be wrong, let me know. Good luck!
EDIT
If you only want to catch the errors inside a specific controller (for example) a controller called Webservice inside your SomethingBundle, you must check it before doing anything:
public function onKernelException(GetResponseForExceptionEvent $event)
{
$request = $event->getRequest();
if($this->getBundle($request) == "Something" && $this->getController($request) == "Webservice")
{
// Do your magic
//...
}
}
private function getBundle(Request $request)
{
$pattern = "#([a-zA-Z]*)Bundle#";
$matches = array();
preg_match($pattern, $request->get('_controller'), $matches);
return (count($matches)) ? $matches[0] : null;
}
private function getController(Request $request)
{
$pattern = "#Controller\\\([a-zA-Z]*)Controller#";
$matches = array();
preg_match($pattern, $request->get('_controller'), $matches);
return (count($matches)) ? $matches[1] : null;
}
DANGER This code is not tested, is only an approach for you to build your own code. But, if I have something wrong on it, tell me. I'd like to keep my examples clean.
Use JsonResponse Symfony class in sandbox:
use Symfony\Component\HttpFoundation\JsonResponse;
$data = array(); // array of returned response, which encode to JSON
$data['error_message'] = 'Bad request or your other error...');
$response = new JsonResponse($data, 500); // 500 - response status
return $response;

ATK4 Form datePicker - default state is 'opened', can this be changed?

I'm using the following form, and everytime the page opens (it's in an expander on a grid) the datePicker is 'open', obscuring part of the text above it.
function page_del() {
$billingid = $_GET['id'];
$now = date("Y-m-d H:i:s");
$q = $this->api->db->dsql()
->table('billing')
->where('id', $billingid)
->field('enddate')
->getOne();
if (!$q) {
$this->add('H5')->set('Are you sure you want to stop billing this item?');
$form = $this->add('Form');
$form->addField('hidden','billingid')->set($billingid);
$form->addField('datePicker','datum')->set($now);
$form->addSubmit('Confirm');
if ($form->isSubmitted()) {
$form->stopBilling('manual', $form, $now);
$this->js()->univ()->getjQuery()->trigger('reload_grid')->execute();
}
} else {
$this->add('H5')->set('This product has already been stopped, effective date: ' .$q);
}
}
}
I have other forms elsewhere that also have a datePicker as their first (visible) field that do not display this behaviour. I only mention it because it looks like a 'focus' issue? I.e. the first field gets focus?
Any thoughts on what causes this or how it can be remedied?
Actually it is field state "onfocus", not default. Your form has only one field and this (first) field is selected on page load.
This behavior is added here:
https://github.com/atk4/atk4/blob/master/lib/Form/Field/DatePicker.php#L35
function addCalendarIcon() {
$this->addButton('',array('options'=>array('text'=>false)))
->setHtml(' ')
->setIcon('ui-icon-calendar')
->js('click',$this->js()->datepicker('show'));
$this->js('focus', $this->js()->datepicker('show'));
}
You can redefine this method in your project and remove line
$this->js('focus', $this->js()->datepicker('show'));