How to format array data in more cleaner way? - php

I have this method:
private function formatCliendCardData($data) {
$formatedData = array();
$formatedData['first_name'] = trim($data['name']);
$formatedData['last_name'] = trim($data['surname']);
$formatedData['date_of_birth'] = $data['birth_year'] . '-' . sprintf("%02d", $data['birth_month_id']) . '-' . sprintf("%02d", $data['birth_day']); //[yyyy-mm-dd]
$formatedData['sex'] = ($data['sex_id'] == 's1'? 'm' : 'f');
$formatedData['county'] = 'Latvija'; //#TODO get real data
$formatedData['post_index'] = (int) preg_replace( '/[^0-9]/', '', $data['post_index']);
$formatedData['city'] = trim($data['city']);
$formatedData['street'] = trim($data['street']);
$formatedData['house_nr'] = trim($data['house_nr']);
$formatedData['phone'] = trim($data['phone']);
$formatedData['email'] = trim($data['email']);
return $formatedData;
}
I run in this problem from time to time. I have big method that just reformats data and returns it. It looks ugly. There is few other aproaches Im aware -- just make foreach loop, but there are exeptions, so i need make 'ifs' anyway. What is better way to reformat such data in your opinon?

I aggree with helloei,
create a class to handle all the formating and validation in the setter.
class Person
{
public function setName($name)
{
$this->name = trim($name);
}
...
}
and then create the object in your function:
private function formatCliendCardData($data) {
$person = new Person();
$person->setName($data['name`])
...

if you have highly custom condition to reformat some datas i think you don't have any other solution that apply this condition manually with some if/else or other custom loop.
if else, you have some unified condition to reformat you can aggregate this and apply in batch at your datas. In other word for my opinion the only other solution are: generalize conditions of your reformatting operations and apply this at your data.
this is Object Oriented approach

IMHO In those cases you have to reduce and clean your code. Often I use an helper function that allows me to split data and formatting rules.
// helper function (OUTSITE YOUR CLASS)
function waterfall($input=NULL,$fns=array()){
$input = array_reduce($fns, function($result, $fn) {
return $fn($result);
}, $input);
return $input;
}
// your formatting rules
$rules = array(
'first_name' => array('trim'),
'last_name' => array('trim'),
'date_of_birth' => array(
'f0' => function($x){
return sprintf("%s-%02d-%02d",
$x['birth_year'],
$x['birth_month_id'],
$x['birth_day']
);
},
'trim'
),
'sex' => array(
'f0' => function($x){
if($x['sex_id'] == 's1'){
return 'm';
}else{
return 'f';
}
}
),
'post_index' => array(
'f0' => function($x){
return (int) preg_replace('/[^0-9]/', NULL, $x);
},
'trim'
),
'city' => array('trim'),
'email' => array('strtolower','trim')
);
// your data
$data = array(
'first_name' => ' Andrea',
'last_name' => 'Ganduglia ',
'date_of_birth' => array(
'birth_year' => '1899',
'birth_month_id' => 5,
'birth_day' => 7
),
'post_index' => 'IT12100',
'city' => 'Rome',
'email' => 'USER#DOMAIN.tld '
);
// put all together
$formatedData = array();
foreach($data as $k => $v){
$formatedData[$k] = waterfall($v,$rules[$k]);
}
// results
print_r($formatedData);
/*
Array
(
[first_name] => Andrea
[last_name] => Ganduglia
[date_of_birth] => 1899-05-07
[post_index] => 12100
[city] => Rome
[email] => user#domain.tld
)
*/

Related

Laravel: Count number of uploads and return those

Using this lib uploading works great. I have number of objects in an excel and I go through them and do whatever I desire.
The question is while uploading the excel I am ought to check whether a particular object already exists, if so increment the $rejected variable otherwise create and increment the $uploaded variable. As a result I would like to return the results: how many uploaded and how many rejected? Whats the best way to do as such? It is obvious I can't access those variables inside the function. What's the best practice here?
public function uploadUsingFile($file)
{
$rejected = 0;
$uploaded = 0;
Excel::load($file, function ($reader) {
foreach ($reader->toArray() as $row)
{
$plateAlreadyExist = Plate::where('serial_number', $row['plate_serial_number'])->exists();
if ($plateAlreadyExist) {
$rejected += 1;continue;
}
$supplier = Supplier::firstOrCreate(['name' => $row['supplier_name']]);
$statusName = EquipmentStatusCode::firstOrCreate(['name' => $row['status_name']]);
$plateType = PlateType::firstOrCreate(['name' => $row['plate_type_name']]);
$process = Process::firstOrCreate(['name' => $row['process_name']]);
$project = Project::firstOrCreate(['name' => $row['project_name']]);
$plateQuality = PlateQuality::firstOrCreate(['name' => $row['plate_quality']]);
$wafer = Wafer::firstOrCreate(['serial_number' => $row['wafer_serial_number']]);
$data = [
'serial_number' => $row['plate_serial_number'],
'crc_code' => $row['crc_code'],
'supplier_id' => $supplier['id'],
'equipment_status_code_id' => $statusName['id'],
'plate_type_id' => $plateType['id'],
'process_id' => $process['id'],
'project_id' => $project['id'],
'plate_quality_id' => $plateQuality['id'],
'wafer_id' => $wafer['id'],
'created_by' => Auth::user()->id,
];
if($data)
{
Plate::create($data);
$uploaded += 1;
}
}
});
return [ 'uploaded' => $uploaded, 'rejected' => $rejected ];
}
You can pass a reference to the variables into the closure by using the use keyword:
...
Excel::load($file, function ($reader) use(&$rejected, &$uploaded){
...
}
Anonymous Functions

Convert ZF2 Service Manager to ZF3

I have a simple ZF2 application that uses two tables and a service and I'm trying to convert it to run on ZF3. I can't work out how to update the service manager code. Here's an example of one of the controllers
<?php
namespace LibraryRest\Controller;
use Zend\Mvc\Controller;
use Library\Service\SpydusServiceInterface;
use Library\Service\SpydusService;
use Library\Model\BookTitle;
use Library\Model\BookTitleTable;
use Library\Model\Author;
use Library\Model\AuthorTable;
use Zend\Mvc\Controller\AbstractRestfulController;
use Zend\View\Model\JsonModel;
class SearchRestController extends AbstractRestfulController {
protected $bookTitleTable;
public function getBookTitleTable() {
if (! $this->bookTitleTable) {
$this->bookTitleTable = $this->getServiceLocator ()->get ( 'BookTitleTable' );
}
return $this->bookTitleTable;
}
protected $authorTable;
public function getAuthorTable() {
if (! $this->authorTable) {
$sm = $this->getServiceLocator ();
$this->authorTable = $sm->get ( 'AuthorTable' );
}
return $this->authorTable;
}
protected $spydusService;
public function __construct(SpydusServiceInterface $spydusService) {
$this->spydusService = $spydusService;
}
public function getList($action, $first, $last) {
if ($action == 'search') {
return $this->searchAction ( $first, $last );
}
}
public function searchAction() {
$message = array ();
$results = array ();
$first = urldecode ( $this->params ()->fromRoute ( 'first' ) );
$last = urldecode ( $this->params ()->fromRoute ( 'last' ) );
if ($this->getAuthorTable ()->getAuthorId ( $first, $last ) === false) {
$results [0] = array ('count' => 0, 'message' => 'This author not found in database', 'first' => $first, 'last' => $last, 'title' => '', 'titleCode' => '', 'link' => '', 'authorId' => '' );
} else {
$authorId = $this->getAuthorTable ()->getAuthorId ( $first, $last )->author_id;
$books = $this->spydusService->searchBooks ( $first, $last );
$count = count ( $books );
foreach ( $books as $foundTitle ) {
if ($foundTitle->getMessage () == 'Nothing found') {
$results [0] = array ('count' => 0, 'message' => 'Nothing found by library search', 'first' => $first, 'last' => $last, 'title' => '', 'titleCode' => '', 'link' => '', 'authorId' => '' );
break;
}
$searchBooks = $this->getBookTitleTable ()->getId ( $foundTitle->getTitle (), $authorId );
if ($searchBooks->count () == 0) {
$addUrl = "http://newlib.rvw.dyndns.org/library/search/add/" . $authorId . '/' . $foundTitle->getTitle ();
$results [] = array ('count' => $count, 'message' => $foundTitle->getMessage (), 'title' => $foundTitle->getTitle (), 'titleCoded' => $foundTitle->getTitleCoded (), 'first' => $foundTitle->getAuthorFirst (), 'last' => $foundTitle->getAuthorLast (), 'link' => $foundTitle->getLink (), 'authorId' => $authorId, 'addUrl' => $addUrl );
}
}
}
if (count ( $results ) == 0) {
$results [0] = array ('count' => 0, 'message' => 'Nothing found by library search', 'first' => $first, 'last' => $last, 'title' => '', 'titleCode' => '', 'link' => '', 'authorId' => '' );
}
return new JsonModel ( $results );
}
}
What code should I use instead of the getServiceLocator() call as this is no longer supported in ZF3? Elsewhere on Stack Overflow someone had replied to another question and suggested using a createService function but this has been dropped from ZF3 as well.
There are a couple of different approaches, but you're already using the most common one: passing the dependencies in through the constructor. You're currently doing this for your $spydusService class, so change the constructor to also accept arguments for the two table clases, something like:
class SearchRestController extends AbstractRestfulController
{
protected $bookTitleTable;
protected $authorTable;
protected $spydusService;
public function __construct(SpydusServiceInterface $spydusService, $bookTitleTable, $authorTable)
{
$this->spydusService = $spydusService;
$this->bookTitleTable = $bookTitleTable;
$this->authorTable = $authorTable;
}
[etc.]
}
then, somewhere you already have a factory for the SearchRestController (it might be a closure in your Module.php class, or a standalone factory class). You'll want to modify this to pass in the extra arguments:
public function getControllerConfig()
{
return array(
'factories' => array(
'SearchRestController' => function ($sm) {
$spydusService = $sm->get('SpydusService'); // this part you already have
$bookTitleTable = $sm->get('BookTitleTable');
$authorTable = $sm->get('AuthorTable');
return new SearchRestController($spydusService, $bookTitleTable, $authorTable);
}
)
);
}
You are going to want to create a factory to build controller. This new class will implement FactoryInterface. In the __invoke function, you'll use the $container instance to retrieve all of your dependencies of your controller and either pass them as arguments in the constructor or set them on the constructor instance. Then just return your controller instance from that function.
Your controller will need to be updated with fields to support this. You will also need to be sure to register your factory in your configuration.

PHP: Rewriting switch as class

So, I have a switch statement inside a foreach loop that checks the value of a field in the array and uses the value to build a named array and email address variable for each unique value. Question is below example code.
As an example, if the values are foo, bar, and foobar, then the following occurs:
switch($value['value']) {
case 'foo':
if(!isset($foo)){
$foo = array();
}
if(!isset($email_foo)){
$email_foo = convert_to_email($value['value']);
}
array_push($foo, $value);
break;
case 'bar':
if(!isset($bar)){
$bar = array();
}
if(!isset($email_bar)){
$email_bar = convert_to_email($value['value']);
}
array_push($bar, $value);
break;
case 'foobar':
if(!isset($foobar)){
$foobar = array();
}
if(!isset($email_foobar)){
$email_foobar = convert_to_email($value['value']);
}
array_push($foobar, $value);
break;
default:
if(!isset($default)){
$default = array();
}
if(!isset($email_default)){
$email_default = 'this#isemail.com';
}
array_push($default, $value);
}
Resulting in 4 different email addresses:
$email_foo = 'foo#isemail.com';
$email_bar = 'bar#isemail.com';
$email_foobar = 'foobar#isemail.com';
$email_default = 'default#isemail.com';
and 4 different arrays of data:
$foo = array(
0 => array(
'value' => 'F Oo',
'name' => 'Janet',
'age' => 23
),
1 => array(
'value' => 'F Oo',
'name' => 'Doug',
'age' => 42
)
)
$bar = array(
0 => array(
'value' => 'B Ar',
'name' => 'James',
'age' => 23
),
1 => array(
'value' => 'B Ar',
'name' => 'Donald',
'age' => 42
)
)
etc...
So, here is the question:
Is it possible to write a class that can be used to create all of the named arrays and email variables? Sort of something like this:
class Account_Manager_Build
{
public function __construct()
{
if(!isset($this)){
$this = array();
}
if(!isset("email_$this")){
"email_$this" = convert_to_email($this->value['value']);
}
array_push($this, $this->value);
}
}
For testing purposes, here is the function convert_to_email that is used throughout the examples:
function convert_to_email($input){
$returned = strtolower(substr($input, 0, 1)).strtolower(end(str_word_count($input, 2))).'#ismail.com';
return $returned;
}
Actually, you can create dynamically variables using the $$ notation:
$variable = "email_$name";
$$variable = "something";
However I'm not sure of what you're trying to do
What's the point of computing $email_something if it can be easily computed from something?
Why do you create those variables instead of just storing this in an array?

Changing key's name in a array

So, having an array like the following:
$input = [
'first_name' => 'Alex',
'last_name' => 'UFO',
'email' => 'test#test.com',
'phone_number' => '124124',
// .....
'referral_first_name' => 'Jason',
'referral_last_name' => 'McNugget',
'referral_email' => 'jingleball#nuggets.com',
'referral_phone_number' => '1212415',
];
After processing the first part, until referral..., do you think of any better way to replace referral_first_name with first_name and so on, then the following? Maybe a more dynamic and automatic way.
$input['first_name'] = $input['referral_first_name'];
unset($input['referral_first_name']);
$input['last_name'] = $input['referral_last_name'];
unset($input['referral_last_name']);
$input['email'] = $input['referral_email'];
unset($input['referral_email']);
$input['phone_number'] = $input['referral_phone_number'];
unset($input['referral_phone_number']);
Guys, I forgot to mention, but I have already done it with foreach, but the problem will be when the array gets pretty large (and usually does, and not by one person using that function, but by many), and that would mean extra unnecessary processing time, since it has to iterate through the whole array, before reaching the referral_.. part.
you must create another array, this code should do it dynamically:
$newInput = array();
foreach($input as $key => $element){
$newKey = explode("_", $key, 2);
$newInput[$newKey[1]] = $element;
}
OUTPUT
hope this helps :-)
Recreating the array is the only way..
Grab all the keys from the original array and put it in a temp array
Use array_walk to modify that temp array to add the referral word to it
Now use array_combine using the above keys and values from the old array.
The code..
<?php
$input = [
'first_name' => 'Alex',
'last_name' => 'UFO',
'email' => 'test#test.com',
'phone_number' => '124124'];
$ak = array_keys($input);
array_walk($ak,function (&$v){ $v = 'referral_'.$v;});
$input=array_combine($ak,array_values($input));
print_r($input);
OUTPUT:
Array
(
[referral_first_name] => Alex
[referral_last_name] => UFO
[referral_email] => test#test.com
[referral_phone_number] => 124124
)
Since you are looking for performance , Use a typical foreach
$newarr = array();
foreach($input as $k=>$v ) {
$newarr["referral_".$k]=$v;
}
How about something like this:
$replace = array('first_name', 'last_name', 'email');
foreach($replace AS $key) {
$input[$key] = $input['referral_' . $key];
unset($input[$input['referral_' .$key]]);
}
try the below one...
$input = [
//'first_name' => 'Alex',
// 'last_name' => 'UFO',
// 'email' => 'test#test.com',
//'phone_number' => '124124',
// .....
'referral_first_name' => 'Jason',
'referral_last_name' => 'McNugget',
'referral_email' => 'jingleball#nuggets.com',
'referral_phone_number' => '1212415',
];
foreach ($input as $key=>$value){
$refereal_pos = strpos($key, 'referral_');
if($refereal_pos !== FALSE && $refereal_pos == 0){
$input[str_replace('referral_', '', $key)] = $value;
unset($input[$key]);
}
}
print_r($input);
You can use following;
function changeKeys($input) {
$keys = array_keys($input);
foreach($keys as $key) {
if (strpos($key, "referral_") !== false) {
$tempKey = explode("referral_", $key);
$input[$tempKey[1]] = $input[$key];
unset($input[$key]);
}
}
return $input;
}
changeKeys($input);
Here is a working demo: codepad
Note: Be sure that, your keys overwrited due to duplicate keys after "referral_" removal

Build custom FILTER_VALIDATE_XY for filter_input_array

I cant find anything about building a custom validation function to use within filter_input_array.
Is there a possibility to validate against one of my own functions?
something like
function FILTER_CUSTOM_FUNCTION($input) { // do something }
$filter = array(
'id' => FILTER_VALIDATE_INT,
'action' => FILTER_SANITIZE_STRING,
'custom_var' => FILTER_CUSTOM_FUNCTION
);
$myArray = filter_input_array(INPUT_GET, $filter);
The solution is the keyword "FILTER_CALLBACK":
function check_languages($var) {
static $called = 0;
$called++;
echo "called: $called: $var<br />";
$var = filter_var($var, FILTER_SANITIZE_STRIPPED);
$l = new language($var);
return $l;
}
$filter = array(
'favourites' => array(
'filter' => FILTER_CALLBACK,
'options' => 'check_languages'
)
);
via http://devzone.zend.com/703/php-built-in-input-filtering/

Categories