npm install node-sass sass-loader style-loader --save-dev
npm install bulma --save // css framework
npm run dev
npm install axions --save // a simple http lib

// jsonplaceholder.typicode.com (# dummy data like comments...)

npm install -g @angular/cli
ng // (| ng -v)
ng new compare-angular --routing style=sass
cd... && ng serve

ng generate component home // (|| ng g c home)

// webpack -> handles frontend modules (require is not valid (build from node.js) and replaces to a valid browser js)

npm install webpack-dev-server --save-dev
// https://codequs.com/p/r1p4sHM5z/continuous-development-without-hitting-ctrl-r-with-webpack-4

Transpiling code means converting the code in one language to code in another similar language. (sass -> css, TS ->JS)

import syntax isn’t much different from the require syntax, but import has extra flexibility for more advanced cases

setup js workflow: https://codequs.com/p/SyIn0WvzQ/modern-javascript-explained-for-dinosaurs

webpack-bundle-analyzer: https://youtu.be/ivQ7HrnBJe8?t=920

hoisting: takes declaration+functions not value to the top
scope: var a = 1; func a = 2 => looks if the a vas defined, if not, looks up
context === this (window === this)
obj.foo.call(window) => zmeni context this v obj na window
#div.slideToggle(300, fnc() {...}.bind(this)); -> outside scope

if(false) { var example = 5 }; console.log(example); // error -> hoisting

arrow functions: let x = num => x * 2;

let x = () => {x + 2}
let x = (x,y) => ({object})

// default values:
func doSmth(param = {prop: value}, prop2: "val") {...}

let dinner = "dinner"
mealPlan = {
    dinner // shorthand of dinner: "dinner"
}

let o5 = ({prop}) => ({prop: prop ? 1 : 0, prop2: prop})
o5({prop})

let ob = {prop1: 1, prop2: 2, prop3: 3}
const pr = ({prop1, prop2}) => ({
    prop1,
    prop2: prop2 ? true : false
})
pr(ob);

// deconstructing obj
var {prop1, prop3: newName} = {prop1: 1, prop2: 2, prop3: 3}
console.log(prop3, newName)

let name = "name", surname = "surname";
let data = { surname, prop1: "prop1", propSur: surname, propInt: 4};
const renameProps = ({prop1: name}) => ({ name, prop1: name});
renameProps(data)
// {name: "prop1", prop1: "prop1"}

// -----------------
function xyz( { weight, height: h, max = 25, callback}) {
	weight * h....
}
xyz({weight, height, max: 30});
xyz({weight, height, callback: function() {} });

// -----------------
var restaurants = [
  {
    cuisine: "Pizza",
    name: "Kubo"
  }, {
    cuisine: "Burger",
    name: "Fuj"
  }
]

const isBurger = ({cuisine}) => cuisine === 'Burger';
const burgerJoints = restaurants.filter(isBurger);

/// -----------

const isCuisine = comparison => ({cuisine}) => cuisine === comparison;

var isCuisineX = function isCuisine(comparison) {
	return function (_ref) {
		var cuisine = _ref.cuisine;
		return cuisine === comparison
	}
}
isCusine("asdf")
restaurants.filter(isBurgerX)

// -----------------

var bunny = {
  name: 'Usagi',
  tasks: ['transform', 'eat cake', 'blow kisses'],
  showTasks: function() {
  this.tasks.forEach(function(task) {
      console.log(this.name + " wants to " + task); // this === window (function = global scope)
    }/*.bind(this)*/);
  }
};

var bunny = {
  name: 'Usagi',
  tasks: ['transform', 'eat cake', 'blow kisses'],
  showTasks() {
	  this.tasks.forEach((task) => { // => references the surrounding scope
		  console.log(this.name + " wants to " + task);
	  });  
  }
};
bunny.showTasks();

// async
async function getUsers(users) {
	try {
		response[0] = await axios.get(`/users/userId=${users[0]}`);
		response[1] = await axios.get(`/users/userId=${users[1]}`);
		response[2] = await axios.get(`/users/userId=${users[2]}`);
		response[3] = await axios.get(`/users/userId=${users[3]}`);
	} catch (err) {
		console.log(err);
	}
}

async function getTop10() {
	const response = await fetch("url...");
	const json = await respon.json();
	
	console.log(json);
}


// map - iterate through array and send each value as an arg via func(val)

// fetch in JS ES6
fetch('https://jsonplaceholder.typicode.com/todos/1')
  .then(response => response.json())
  .then(json => console.log(json))

// for (let income of incomes) ... 

// rest operator (check spread operator) 
let test = (...args) => console.log('args: ', args[3]);
test(1,2,3,4)

["a","b","c"].includes("a") // true

// import export
// file:modules.js
export const data = [1,2,3];
// file:index.js
import { data } from './modules.js'

// ------------helpers--------------------

_has = function(obj, key) {
        return Object.prototype.hasOwnProperty.call(obj, key);
      }

var lazy = [].slice.call(document.querySelectorAll(".test"));
lazy.forEach(item =>item.classList.add("visible"));

// CLASS 

export class Test {
	constructor(param) {
		this.param = param;
	}
	
	static test() { return 1010; }
	
	get prop() { return `getter ${this.param}`; }
}
import Test from '....'
let test = new Test("asdf");


// generators
var myGen = function*() {
	var one = yield "foo";
	var two = yield "bar";
	console.log('log:', one, two); // 2, a
}
var gen = myGen();

console.log(gen.next());
console.log(gen.next(2));
console.log(gen.next("a"));
console.log(gen.next("b"));

Promise.coroutine(function* () {
	var data = yield { 
		tweets: $.get('tweets.json'),
		profile: $.get(...)
	};
	console.log(data.tweets, ...)
})();

// ---------------------------------- reduce + filter


json.reduce((accumulator, item) => {accumulator[item.gender] => item}, {male:[], female: []});

json = [{i:1}, {i:2}, {i:3}, {i:4}]

Array.prototype.filter = function(fn) {
    return this.reduce((items, item, index) => {
      if(fn(item))
        items.push(item);
		
		return items;
	}, []);
}

arr = json.filter(item => item.i >= 2);
console.log(arr);


Array.prototype.forEach = function(fn) {
	this.reduce((acc, item, index) => {
		item = fn(item, index)
	},[]);
};

arr.forEach( (item, index) { do something } );


json.map(item => item.DB_ID);

// ---------------- pew pew filter
// https://css-tricks.com/level-up-your-filter-game/

const isKeyEqualToValueX = key => value => object => object[key] === value;

var isKeyEqualToValue = function isKeyEqualToValue(key) {
  return function (secondCallValue) {
    return function (filterItem) {
      return filterItem[key] === secondCallValue
    }
  }
}

const isCuisine = isKeyEqualToValue('cuisine');
const isBurger    = isCuisine('Burger');
const burgers = restaurants.filter(isBurger)


// --------------------- promises

let cleanRoom = function () {
	return new Promise((resolve, reject) {
		resolve('this will be returned as an argument in .then');
	}
}
cleanRoom().then(result => {
	return anotherPromise(result);
});

Promise.all([all promises to run]).then(() => console.log('all done'));
// Promise.race -> first finished returns

observable -> stream of data / definition / wrapper for some functionality
observer -> executes a code when new value is recieved -> subscribes to observable

observable [-----[next()]-----[next()]----...]
				 observer	  observer 
				 
react:
storybook
gatsby js (static js generator based on graphql)
nextjs

// -----------------------------------------------
// NG ----------------------------------------------
// -----------------------------------------------

attributes - HTML -> used to init DOM, cannot change
properties - DOM -> angular:  myId is defined in the NG component class | used for NOT string values
	 directives with template ->  -> will be rendered with custom html/css
directive ->  -> structural dom change

// 2 way binding (bannana in a box) [()]
...
...

...html...
...html...

https://youtu.be/RhemSul_Up0?t=5225
component 
@Input() public propNameFromParent -> recieving data from parent (|| @Input("propNameFromParent") public myName
@Output() public childEvent = new EventEmitter(); -> child sending to parent -> as we dont have parent elemnt component we send events
>> this.childEvent.emit("some data")...

...

// ovservables
- an observable is a sequence of items that arrive async over time (an HTTP response)

// https://youtu.be/RhemSul_Up0?t=8781 (+catch)
service: getMethod(): Observable{ 
	return this.http.get(("...url...");
}

// routing: https://youtu.be/RhemSul_Up0?t=9339
https://youtu.be/RhemSul_Up0?t=11783 (relativeRouting)

// read GET param: https://youtu.be/RhemSul_Up0?t=10573 (ActivatedRoute)
this.route.snapshot.paramMap.get('id')

// progressive web app PWA
https://itnext.io/turning-an-angular-6-app-into-a-progressive-web-app-9e6fc6361ba6
https://medium.com/progressive-web-apps/a-new-angular-service-worker-creating-automatic-progressive-web-apps-part-1-theory-37d7d7647cc7
https://medium.com/google-developer-experts/a-new-angular-service-worker-creating-automatic-progressive-web-apps-part-2-practice-3221471269a1
google PWA checklist


// Lighthouse 
lighthouse http://localhost:8080 --view (runs the test and spits out a report)

headless chrome 
calibre tool


stencil ionic web component -> performance
capacitor
cross device build: 
https://medium.com/@Amit_Shukla/deploy-angular-6-0-html-js-css-app-to-mobile-web-and-desktop-using-ionic-capacitor-106e84d66a96

test:
test:

Building an Ionic Geolocation Tracker with Google Map and Track Drawing


https://github.com/syedmoosakaleem95/Ionic-3—Google-Maps-API
https://capacitor.ionicframework.com/docs/apis/haptics

Ionic Local Notifications (Schedule, Payload and Callback) [v3]

Share This:

  • Comments Off on JS in 2018 – list of all the things I read

source from: https://codepen.io/mxbck/pen/EvmLVp/

/*
 * Variables
 */

:root {  
  --card-padding: 24px;
  --card-height: 340px;
  --card-skeleton: linear-gradient(lightgrey var(--card-height), transparent 0);
  
  --avatar-size: 32px;
  --avatar-position: var(--card-padding) var(--card-padding);
  --avatar-skeleton: radial-gradient(circle 16px at center, white 99%, transparent 0
  );
  
  --title-height: 32px;
  --title-width: 200px;
  --title-position: var(--card-padding) 180px;
  --title-skeleton: linear-gradient(white var(--title-height), transparent 0);
  
  --desc-line-height: 16px;
  --desc-line-skeleton: linear-gradient(white var(--desc-line-height), transparent 0);
  --desc-line-1-width:230px;
  --desc-line-1-position: var(--card-padding) 242px;
  --desc-line-2-width:180px;
  --desc-line-2-position: var(--card-padding) 265px;
  
  --footer-height: 40px;
  --footer-position: 0 calc(var(--card-height) - var(--footer-height));
  --footer-skeleton: linear-gradient(white var(--footer-height), transparent 0);
  
  --blur-width: 200px;
  --blur-size: var(--blur-width) calc(var(--card-height) - var(--footer-height));
}

/*
 * Card Skeleton for Loading
 */

.card {
  width: 280px; //demo
  height: var(--card-height);
  
  &:empty::after {
    content:"";
    display:block;
    width: 100%;
    height: 100%;
    border-radius:6px;
    box-shadow: 0 10px 45px rgba(0,0,0, .1);

    background-image:
      linear-gradient(
        90deg, 
        rgba(lightgrey, 0) 0, 
        rgba(lightgrey, .8) 50%, 
        rgba(lightgrey, 0) 100%
      ),                          //animation blur
      var(--title-skeleton),      //title
      var(--desc-line-skeleton),  //desc1
      var(--desc-line-skeleton),  //desc2
      var(--avatar-skeleton),     //avatar
      var(--footer-skeleton),     //footer bar
      var(--card-skeleton)        //card
    ;

    background-size:
      var(--blur-size),
      var(--title-width) var(--title-height),
      var(--desc-line-1-width) var(--desc-line-height),
      var(--desc-line-2-width) var(--desc-line-height),
      var(--avatar-size) var(--avatar-size),
      100% var(--footer-height),
      100% 100%
    ;
    
    background-position:
      -150% 0,                      //animation
      var(--title-position),        //title
      var(--desc-line-1-position),  //desc1
      var(--desc-line-2-position),  //desc2
      var(--avatar-position),       //avatar
      var(--footer-position),       //footer bar
      0 0                           //card
    ;

    background-repeat: no-repeat;
    animation: loading 1.5s infinite;
  }
}

@keyframes loading {
  to {
    background-position:
      350% 0,        
      var(--title-position),  
      var(--desc-line-1-position),
      var(--desc-line-2-position),
      var(--avatar-position),
      var(--footer-position),
      0 0
    ;
  }
}

/* 
 * Demo Stuff
 */

body {
  min-height:100vh;
  background-color:#FFF;
  display:flex;
  justify-content:center;
  align-items:center;
}

Share This:

  • Comments Off on Sekeleton App in Pure CSS

SCSS crash course; aka – collection of existing sources used as a reminder for myself, and perhaps some random dude…

$settings: (
    maxWidth: 800px,
    columns: 4,
    margin: 15px,
    breakpoints: (
        xs: "(max-width : 480px)",
        sm: "(max-width : 768px) and (min-width: 481px)",
        md: "(max-width : 1024px)  and (min-width: 769px)",
        lg: "(min-width : 1025px)"
    )   
);

@mixin renderGrid($key, $settings, $default: "xyz") {
    @if $key {
        $key: "xs";
    } @else {
        // ...
    }
    
  $i: 1;
  @while $i <= map-get($settings, "columns") {
    .col-#{$key}-#{$i} {
      float: left;
      width: 100% * $i / map-get($settings,"columns");
    }
    $i: $i+1;
  }
};

@include renderGrid("lg", $settings);

.container {
    padding-right: map-get($settings, "margin");
    padding-left: map-get($settings, "margin");
    margin-right: auto;
    margin-left: auto;
};

.row {
    margin-right: map-get($settings, "margin") * -1;
    margin-left: map-get($settings, "margin") * -1;
};


// ------------------------ @mixin ...
@mixin padding($values) {    
    @each $var in $values {
        padding: #{$var};
    }
}
// @include padding(2px 4px 6px);
// @include padding($values...);

$style1: 100%, 70px, #fo6d06;
$style2: (background: #bada55, width: 100%, height: 100px);
@mixin box($width, $height, $background) {
    width: $width;
    height: $height;
    background-color: $background;
}

.badass {
    @include box($style1...);
    @include box($style2...);
}

// -------------------------------- @content
@mixin apply-to-ie6-only {
  * html {
    @content
  }
}

@include apply-to-ie6-only {
  #logo {
    background-image: url(/logo.gif);
  }
}

@mixin media($width) {
  @mediaX only screen and (max-width: $width) {
    @content
  }
}

@include media(320px) {
  background: red;
}

/* ------------------------- keyframes */

@mixin keyframes($name) {
  @-webkit-keyframes #{$name} {
    @content;
  }

  @-moz-keyframes #{$name} {
    @content;
  }

  @keyframes #{$name} {
    @content;
  }
}

@include keyframes(fadeIn) {
  from {
    opacity: 0%;
  }
  to {
    opacity: 100%;
  }
}

/* -------------------- header ----------------*/

@mixin create-context($classes...) {
  @each $class in $classes {
    .#{$class} & {
      @content;
    }
  }
}

@mixin context--alternate-template {
  @include create-context(about, blog) {
    @content
  }
}


.header {
  height: 12em;
  background: red;

  @include context--alternate-template {
    background: green;
  }
}

/* ---------------------- placeholder ----------------- */
%button {
  min-width: 100px;
  padding: 1em;
  border-radius: 1em;
}
%twitter-background {
  color: #fff;
  background: #55acee;
}
%facebook-background {
  color: #fff;
  background: #3b5998;
}

.btn {
  &--twitter {
    @extend %button;
    @extend %twitter-background;
  }
  &--facebook {
    @extend %button;
    @extend %facebook-background;
  }
}

/* --------------------- extend -------------------------*/

.icon {
  transition: background-color ease .2s;
  margin: 0 .5em;
}

.error-icon {
  @extend .icon;
  /* error specific styles... */
}

.info-icon {
  @extend .icon;
  /* info specific styles... */
}

Share This:

  • Comments Off on SCSS and CSS in 2018 – my long overdue updates of what’s possible

Why you should reconsider your decision – support

Let me give you one example… let’s say you need to submit your homework or need to access your class, etc. Now imagine that the website and the whole university portal is down twice a week (which is not uncommon), so what you do? You contact technical support. They will probably answer within 24h (like this is helpful if your deadline is in next few hours). You explain your problem, and this is what you get:

1. Clear your browsers’ cache and cookies (after clearing your cache, please close all browser windows and start a new browser session) www.refreshyourcache.com
2. Close the browser, then re-open it.
3. Try an alternate browser (Internet Explorer, Firefox, or Chrome).
4. Reboot the computer/laptop.
5. Try a different computer/laptop.

So you take a deep breath, you try to explain you did all of that, and if you get some answer at all (which is not uncommon for them not to answer at all) you get something like this:

…it appears to be some kind of computer issue on your end causing this issue.

Thank you very much for nothing (as usual). You try to take another deep breath and explain that unless they won’t borrow you their PC, it is not going to solve your problem. After that, they usually stop answering for good.

You try to log the next day and suddenly everything works as expected… issue on my pc? Let me be clear here! I didn’t reboot my PC at this point, not even closed my browser…

Now you might be thinking; this guy is just moaning… yes, I tried contacting them, by phone, email, wrote an official complain, participated in their surveys… no change at all, same shit all the time…

This is only a tip of an iceberg and I’m going to post every shit they did and will do from no one until they will realize they can’t ignore customers paying 1.3k for one module and get away with this shit.

Kirk out

Share This:

  • Comments Off on The University of Liverpool – support

The config for IPTables is located:
/etc/sysconfig/iptables

I added the following line to it:
-A INPUT -p tcp -m state --state NEW -m tcp --dport 6379 -j ACCEPT

Reloaded IPtables:
sudo service iptables reload

Sanity check:
sudo iptables -S

Share This:

  • Comments Off on Allowing Redis port – iptables

short answer – you can’t…

shorter answer – use stat:
stat -c '%A %a %n' *

Share This:

  • Comments Off on ls – how to get octal file permission

Checking nested structure with isset does not work anymore!

In the project I’m working on currently, all the models extends from ArrayObject:

abstract class AbstractModel extends ArrayObject

Now, I found the following on many places (or similar-ish):


if (isset($brandModel->extra->espInformation->folders->folderItems)) {
    return $brandModel->extra->espInformation->folders->folderItems;
}

The brand model:

class Brands extends AbstractModel
{
    private $extra = 'hey!!!';
    // some more public/protected properties
}

Before, if I would check for properties inside the model with isset($this->$key), however, this is no longer working if the property is private!!! Isset is not a function so it was not throwing an error on checking not existing indexes/properties.

The code before:

    public function __isset($key)
    {
        if ($this->flag == self::ARRAY_AS_PROPS) {
            return $this->offsetExists($key);
        }

        // will return false >= php7.0.6
        return isset($this->$key);
    }

Now

    public function __isset($key)
    {
        if ($this->flag == self::ARRAY_AS_PROPS) {
            return $this->offsetExists($key);
        }

        /**
         * nasty PHP 7.0.6 "fix" #62059 && #69659
         * isset is not working properly anymore
         * and will not evaluate inner arrays or private properties
         * and thus we have to steal the private and check isset on value rather than object
         */
        $reader = function &($object, $property) {
            $value = &\Closure::bind(
                function &() use ($property) {
                    return $this->$property;
                },
                $object,
                $object
            )->__invoke();

            return $value;
        };

        $value = &$reader($this, $key);

        return isset($value);
    }

The isset is however working on protected and public, only accessing private properties is messed up.

Furthermore, they argue it is a “bugfix” (if you bother to read the issue comments), however, I think it is extremely stupid to fix such a important function in a minor release. Shame on you!!!

PS: credit for stealing cookies goes to Ocramius 😉 https://ocramius.github.io/blog/accessing-private-php-class-members-without-reflection/

Share This:

  • Comments Off on PHP 7.0.6 isset not working properly – anymore

February 9, 2016 | In: Programovanie

SVN repo size

svn list -vR file:///path/to/svn/folder/* | awk '{if ($3 !="") sum+=$3; i++} END {print "\ntotal size= " sum/1024000" MB" "\nnumber of files= " i/1000 " K"}'

Share This:

  • Comments Off on SVN repo size

how to run phan on debian

First, go here, here and here to get an idea about how to get phan working.

For Debian8 though, I had to do a few more tricks to get it running.

If you still haven’t try php7 (shame on you!) check this guide: how to install php7 on debian8 and redhat6.

To compile phan, you will need a phpize. For some reason it couldn’t resolve the dependencies automatically so here is what you will need:

aptitude install autoconf automake autotools-dev libltdl-dev libssl-dev libssl-doc libtool shtool

than php readline and sqlite3:

aptitude install php7.0-readline php7.0-sqlite3

and finally you should be able to install:

aptitude install php7.0-dev

You can now go back to phan and you should be able to compile it (finally):

$ git clone git@github.com:nikic/php-ast.git
$ cd php-ast
$ phpize7.0
$ ./configure --enable-ast 
$ make install

This will build your ast.so, which is located (on debian8):

ls /usr/lib/php/20151012/

Now you need to configure php-cli and load your new module. Check where the all the interesting ini/conf files are:

php --ini

On Debian you probably want to check:

cd /etc/php/7.0/cli/conf.d/
echo 'extension=ast.so' > 20-ast.ini

If everything went fine (like it ever does…), you are good to go with phan install:

$ composer global require etsy/phan:dev-master

That should do the trick and you can run phan from your command line:

cd my_php_project;
phan -i -b -p `find ./ -type f -path '*.php'` > static_anal.report

And if you are lucky enough, and wont end up with segmentation fault as I did (try to run it on sub folder), you will see a lot of interesting things:

.../NeolaneController.php:72 TypeError assigning object to property but \default_neolanecontroller::proxy is array
.../ExactTarget/Et.php:258 ParamError call with 4 arg(s) to \soapvar::__construct() which only takes 0 arg(s)
.../CreateTextVersionDynamic.php:318 TypeError string passed to foreach instead of array
.../Editors/HTMLEditor.php:99 VarError Variable $element is not defined
.../Editors/DynamicEmails.php:105 TypeError arg#2(search) is \Service\Editors\stdclass but \array_key_exists() takes array
.../Editors/DynamicEmails.php:703 TypeError arg#2(subject) is string but \preg_replace_callback_array() takes array
.../Editors/DynamicEmails.php:721 TypeError arg#1(masterId) is int but \Service\Editors\dynamicemails::setmasterid() takes \Service\Editors\type defined at .../Editors/DynamicEmails.php:767
.../Editors/DynamicEmails.php:912 ParamError call with 3 arg(s) to \Service\Editors\dynamicemails::createviewrow() which only takes 2 arg(s) defined at .../Editors/DynamicEmails.php:926
.../Accounts.php:261 TypeError return \Service\type but getUsers() is declared to return array

If you want to experiment with other libraries, checkout the post from php7 analysis tools.

Share This:

  • Comments Off on running phan static analyzer to check php5 to php7 issues

December 9, 2015 | In: Programovanie

php7 Anonymous Classes

Anonymous Classes

It is exactly what it says, but when can it be useful?

Ever found your self refactoring a pile of shit like the following code?

public function getEmail()
{
    // Now that we have the email we will save it as an object
    // on this class
    $emailObj = new \stdClass();
    $Results = new \stdClass();
    $Results->ID = $emailFromDb->id;
    $Results->HTMLBody = ...;
    $Results->TextBody = ...;
    ... more shit ...
    $emailObj->Results = $Results;

    return $emailObj;
}

// and here we go
public function getTemplateInformation($templateId)
{
    $emailObj = $this->getEmail($templateId);
    
    $data = (array)$emailObj;
    foreach ($data as $property => $value) {
        // do some black magic
    }
    
    $result = [
        "senderAddress" => "test1@test1.com",
        "subject" => '',
        "startDateTime" => '',
        "senderName" => "",
        "label" => isset($this->email->Results->Subject) ? $this->email->Results->Subject : "",
        "isModel" => 1,
    ];

    return (object)$result;
}

and then wherever you look you see casting it back to array?

$data = (array)$email;
foreach ($data as $property => $value) {
...

and then somewhere else

        $emailData = (object)[
            'emailId' => $emailId,
            'folderId' => $folderId,
            'emailWrapper' => $emailParts['container']
        ];

and some more

$result = (array)$result;
foreach ($result as $property => $value) {
...

and some more

    public function getTemplateInformation($templateId)
    {
        return (object)[
            \Service\EditorAbstract::EMAIL_TYPE => null,
            \Service\EditorAbstract::EMAIL_MASTER_ID => $this->templateMapper->getMasterForTemplate($templateId)
        ];
    }

Finding your self doing something like that? Then stop it! Seriously!

You know by now that you want to replace it with some model or real object, but you want to do it step by step and not brake anything.
Now how to do it? The answer is refactoring. I found anonymous classes super useful when replacing crap like that. As first step you can define anonymous class to confirm that everything still works as expected (if you have unit tests, if not – heaven help you!). And start replacing all the crap with your new object:


public function getTemplateInformation($templateId)
{
    $result = [
        "senderAddress" => "test1@test1.com",
        "subject" => '',
        "startDateTime" => '',
        "senderName" => "",
        "isModel" => 1,
    ];

    return new class($result) extends \Model\AbstractModel
    {
        function __construct($result)
        {
            // make the black magic here
        }
    };
}

And what you get is the nice model ready to be tested and you are ready for next steps.

more about php7:

if you need to install PHP7 check out this article

php7 null coalesce operator ??

php7 class return type

Share This:

  • Comments Off on php7 Anonymous Classes