/ Gists

Gists

On gists

Klogger

PHP Libs

Klogger.php #

<?php
	
	/* Finally, A light, permissions-checking logging class. 
	 * 
	 * Author	: Kenneth Katzgrau < katzgrau@gmail.com >
	 * Date	: July 26, 2008
	 * Comments	: Originally written for use with wpSearch
	 * Website	: http://codefury.net
	 * Version	: 1.0
	 *
	 * Usage: 
	 *		$log = new KLogger ( "log.txt" , KLogger::INFO );
	 *		$log->LogInfo("Returned a million search results");	//Prints to the log file
	 *		$log->LogFATAL("Oh dear.");				//Prints to the log file
	 *		$log->LogDebug("x = 5");					//Prints nothing due to priority setting
	*/
	
	class KLogger
	{
		
		const DEBUG 	= 1;	// Most Verbose
		const INFO 		= 2;	// ...
		const WARN 		= 3;	// ...
		const ERROR 	= 4;	// ...
		const FATAL 	= 5;	// Least Verbose
		const OFF 		= 6;	// Nothing at all.
		
		const LOG_OPEN 		= 1;
		const OPEN_FAILED 	= 2;
		const LOG_CLOSED 	= 3;
		
		/* Public members: Not so much of an example of encapsulation, but that's okay. */
		public $Log_Status 	= KLogger::LOG_CLOSED;
		public $DateFormat	= "Y-m-d G:i:s";
		public $MessageQueue;
	
		private $log_file;
		private $priority = KLogger::INFO;
		
		private $file_handle;
		
		public function __construct( $filepath , $priority )
		{
			if ( $priority == KLogger::OFF ) return;
			
			$this->log_file = $filepath;
			$this->MessageQueue = array();
			$this->priority = $priority;
			
			if ( file_exists( $this->log_file ) )
			{
				if ( !is_writable($this->log_file) )
				{
					$this->Log_Status = KLogger::OPEN_FAILED;
					$this->MessageQueue[] = "The file exists, but could not be opened for writing. Check that appropriate permissions have been set.";
					return;
				}
			}
			
			if ( $this->file_handle = fopen( $this->log_file , "a" ) )
			{
				$this->Log_Status = KLogger::LOG_OPEN;
				$this->MessageQueue[] = "The log file was opened successfully.";
			}
			else
			{
				$this->Log_Status = KLogger::OPEN_FAILED;
				$this->MessageQueue[] = "The file could not be opened. Check permissions.";
			}
			
			return;
		}
		
		public function __destruct()
		{
			if ( $this->file_handle )
				fclose( $this->file_handle );
		}
		
		public function LogInfo($line)
		{
			$this->Log( $line , KLogger::INFO );
		}
		
		public function LogDebug($line)
		{
			$this->Log( $line , KLogger::DEBUG );
		}
		
		public function LogWarn($line)
		{
			$this->Log( $line , KLogger::WARN );	
		}
		
		public function LogError($line)
		{
			$this->Log( $line , KLogger::ERROR );		
		}

		public function LogFatal($line)
		{
			$this->Log( $line , KLogger::FATAL );
		}
		
		public function Log($line, $priority)
		{
			if ( $this->priority <= $priority )
			{
				$status = $this->getTimeLine( $priority );
				$this->WriteFreeFormLine ( "$status $line \n" );
			}
		}
		
		public function WriteFreeFormLine( $line )
		{
			if ( $this->Log_Status == KLogger::LOG_OPEN && $this->priority != KLogger::OFF )
			{

			    if (fwrite( $this->file_handle , $line ) === false) {
			    	
			        $this->MessageQueue[] = "The file could not be written to. Check that appropriate permissions have been set.";
			    }
			}
		}
		
		private function getTimeLine( $level )
		{
			$time = date( $this->DateFormat );
		
			switch( $level )
			{
				case KLogger::INFO:
					return "$time - INFO  -->";
				case KLogger::WARN:
					return "$time - WARN  -->";				
				case KLogger::DEBUG:
					return "$time - DEBUG -->";				
				case KLogger::ERROR:
					return "$time - ERROR -->";
				case KLogger::FATAL:
					return "$time - FATAL -->";
				default:
					return "$time - LOG   -->";
			}
		}
		
	}


On gists

Exchange rates solution (AMI)

PHP Libs PHP

ExchangeRatesFetcher.php #

<?php
/**
 * Abstraktni trida pro stahovani kurzovnich listku ze stranek bank
 *
 * @date 25-02-2008
 * @version 1.0
 *
 */
abstract class ExchangeRatesFetcher
{
	/**
	 * URL, odkud se kurzy stahuji
	 * 
	 * @var string	 	 
	 */
	protected $url;
	
	/**
	 * kod banky 
	 * 
	 * @var string	 	 
	 */
	protected $bank_code;

	/**
	 * seznam kodu men, ktere chceme stahovat
	 * 
	 * @var array
	 */	 	 	 	
	protected $important_currencies = array('CAD', 'DKK', 'EUR', 'GBP', 'HUF', 'CHF', 'JPY', 'NOK', 'PLN', 'SEK', 'SKK', 'USD', 'RON', 'RUB', 'AUD');
	
	/**
	 * pole stazenych hodnot kurzu
	 * 
	 * @var array	 	 
	 */
	protected $exchange_rates = array();
	
	/**
	 * konstruktor - nastaveni vychozich hodnot
	 * 
	 * @param  string  URL, odkud se kurzy stahuji
	 */
	public function __construct($url)
	{
		$this->url = $url;
	}
	
	/**
	 * funkce vraci pole stazenych kurzu (vhodne napr. pro testovaci vypisy)
	 * 
	 * @return array/false pokud nejsou stazene kurzy vraci false, jinak vraci pole stazenych kurzu 
	 */	 	
	public function getExchangeRates()
	{
		if (is_array($this->exchange_rates)) {
			return $this->exchange_rates;
		}
		else {
			return false;
		}
	}

	/**
	 * funkce vraci kod banky
	 * 
	 * @return string 
	 */	 	
	public function getBankCode()
	{
		return $this->bank_code;
	}
	
	/**
	 * Funkce pro stahnuti kurzovniho listku
	 * 	 	
	 * Funkce stahne kurzovni listek a ulozi ho do interni promenne $exchange_rates
	 */	 	  	 	
	abstract public function fetch();
}

On gists

Elo rating

Formulas

elo.php #

<?php

session_start();
//$_SESSION['player_rating'] = 1000; //reset player to default

//get saved player rating
if(isset($_SESSION['player_rating'])){
	$player_rating	= $_SESSION['player_rating'];
} else {
	$player_rating	= 1000;
}
$opponent_rating = rand(0, 2000);	

echo "Player Ranking: ".$player_rating."<br>";
echo "Opponent Ranking: ".$opponent_rating."<br>";

//formula explained - http://forums.steampowered.com/forums/showthread.php?t=1220287
$chance_of_winning = abs((1 / ( 1 + pow(10, ( ($opponent_rating - $player_rating) / 400) ) )) * 100); //percentage
$chance_of_losing = abs(100 - $chance_of_winning); //percentage

//output chances
echo $chance_of_winning."% chance of winning.<br>";
echo $chance_of_losing."% chance of losing.<br>";

//evaluate and output win and lose points
$k_factor = 32; //a common k factor
$win_points = round($k_factor *  ($chance_of_losing/100)); //k_factor * decimal number
$lose_points = round($k_factor * ($chance_of_winning/100)); //k_factor * decimal number
echo '$win_points: '.$win_points.'<br>';
echo '$lose_points: '.$lose_points.'<br>';

//play game - even odds
if($chance_of_winning > 50){
	$player_rating = $player_rating + $win_points;
	echo "<br><strong>Player Wins</strong><br>";	
	echo "Player Earns $win_points points<br>";	
} else {
	$player_rating = $player_rating - $lose_points;
	$player_rating = ($player_rating < 0 ) ? 0 : $player_rating;
	echo "<br><strong>Player Loses</strong><br>";	
	echo "Player Loses $lose_points points<br>";	
}

//record player rating
$_SESSION['player_rating'] = $player_rating;

echo "Player Ranking: " . $player_rating . "<br>";

On gists

Function object with inside small functions

JavaScript-OOP JavaScript

example.js #

var Wrapper = (function () {
	this.A = () => {
		console.log('A');
	}
	this.B = () => {
		console.log('B');
	}
	
	return {
		A2: this.A,
		B2: this.B
	}

	// or return this
})();


Wrapper.B2(); // B

On gists

24. Value -> Object

PHP Patterns

example1.php #

<?php
// https://forum.nette.org/cs/34970-rozne-ceny-za-roznych-okolnosti#p218919
class Product
{
	private Price $price;

	public function getPrice(): Price
	{
		return $this->price;
	}
}

//

	public function getPrice(...$modifiers): Price
	{
		$price = $this->price;
		foreach($modifiers as $modifier) {
			$price = $price->modify($modifier);
		}
		return $price;
	}
	
	//
	
	class PriceResolver
{
	private array $modifiers = [];

	public function setCustomer(IModifier $modifier): void
	{
		$this->modifiers[] = $modifier;
	}

	public function setSeason(IModifier $modifier): void
	{
		$this->modifiers[] = $modifier;
	}

	public function setOtherRule(IModifier $modifier): void
	{
		$this->modifiers[] = $modifier;
	}

	public function resolve(Product $product): Price
	{
		$price = $product->getPrice();
		foreach($modifiers as $modifier) {
			$price = $price->modify($modifier);
		}
		return $price;
	}
}

class Price
{
    private float $amount;
    private string $currency;

    public function __construct(float $amount, string $currency)
    {
        $this->amount = $amount;
        $this->currency = $currency;
    }

    public function getAmount(int $precision = 2): float
    {
        return round($this->amount, $precision);
    }

    public function getCurrency(): string
    {
        return $this->currency;
    }

    public function modify(Modifier $modifier): Price
    {
        if($modifier->isPercentage()) {
            $amount = $this->getAmount(4) * (100 + $modifier->getAmount()) / 100;
        }
        else {
            $amount = $this->getAmount(4) + $modifier->getAmount();
        }
        return new self($amount, $this->currency);
    }

    public function multiply(float $multiplier): Price
    {
        return new self($this->amount * $multiplier, $this->currency);
    }

    public function divide(float $divisor): Price
    {
        return new self($this->amount / $divisor, $this->currency);
    }

    public function add(Price $price): Price
    {
        if($this->currency !== $price->getCurrency()) {
            throw new CurrencyMismatchException("Currency missmatch");
        }
        return new self($this->amount + $price->getAmount(4), $this->currency);
    }

    public function minus(Price $price): Price
    {
        if($this->currency !== $price->getCurrency()) {
            throw new CurrencyMismatchException("Currency missmatch");
        }
        return new self($this->amount - $price->getAmount(4), $this->currency);
    }

    public function equals(Price $other): bool
    {
        return $this->getAmount(4) === $other->getAmount(4) and $this->currency === $other->getCurrency();
    }
}

class Modifier
{
    const TYPE_PERCENTAGE = "P";
    const TYPE_ABSOLUTE = "A";

    private string $type;
    private float $amount;

    public function __construct(string $type, float $amount)
    {
        $this->type = $type;
        $this->amount = $amount;
    }

    public function getType(): string
    {
        return $this->type;
    }

    public function getAmount(int $precision = 2): float
    {
        return round($this->amount, $precision);
    }

    public function cumulate(Modifier $modifier): Modifier
    {
        if($this->type !== $modifier->getType()) {
            throw new TypeMissmatchException("Type missmatch");
        }
        return new self($this->type, $this->amount + $modifier->getAmount(4));
    }

    public function isPercentage(): bool
    {
        return $this->type === self::TYPE_PERCENTAGE;
    }

    public function isAbsolute(): bool
    {
        return $this->type === self::TYPE_ABSOLUTE;
    }
}

On gists

Nette 2.4 - custom filters - class

Nette Nette-Latte

SotioFilters.php #

<?php

namespace App\FrontModule\Filters;

use Nette;
use Andweb;

class SotioFilter
{

	/**
	 * Andweb\Localization\ITranslator
	 */
	private $translator;

	public function __construct(Andweb\Localization\ITranslator $translator)
	{
		$this->translator = $translator;
	}


	public function register($template)
    {
        $template->addFilter(null, [$this, 'loader']);
    }


	public function loader($filter)
	{
		if (method_exists(__CLASS__, $filter)) 
		{
            $args = func_get_args();
            array_shift($args);
            return call_user_func_array(array(__CLASS__, $filter), $args);
		}

		return NULL;
	}


	public function readMore($s)
	{
		$s = preg_replace('~(<div>--START--</div>)(.+)<div>--END--</div>~Usi', 
			'<div class="read-more-wrapper">$2</div><div class="read-more-btn-wrapper"><a href="">'.$this->translator->translate('READ MORE').'</a></div>',
			 $s
		);

		return $s;
	}


}

On gists

$attrs

Vue.js

index.vue #

<template>
  <div>
    <p>
      <custom-checkbox>Simple example</custom-checkbox>
    </p>
    <p>
      <custom-checkbox :disabled="true">Disabled</custom-checkbox>
    </p>
  </div>
</template>

<script>
import CustomCheckbox from './CustomCheckbox'
export default {
  components: { CustomCheckbox }
}
</script>

<style scoped>

</style>

On gists

Recursion

Vue.js

index.vue #

<template>
  <div>
    <tree-list
      :children="treeItems"
      :parents="[]"
    />
  </div>
</template>

<script>
  import TreeList from './TreeList.vue'

  export default {
    components: {TreeList},
    compontents: {
      TreeList
    },
    data () {
      return {
        treeItems: [
          {
            title: 'First top level',
            children: [
              {
                title: 'First sub level',
                children: [
                  {title: 'First sub-sub level'},
                  {title: 'Second sub-sub level'},
                  {title: 'Third sub-sub level'}
                ]
              },
              {
                title: 'Second sub level',
                children: [
                  {title: 'First sub-sub level'},
                  {title: 'Second sub-sub level'},
                  {title: 'Third sub-sub level'}
                ]
              },
              {
                title: 'Third sub level',
                children: [
                  {title: 'First sub-sub level'},
                  {title: 'Second sub-sub level'},
                  {title: 'Third sub-sub level'}
                ]
              }
            ]
          },
          {
            title: 'Second top level',
            children: [
              {
                title: 'First sub level',
                children: [
                  {title: 'First sub-sub level'},
                  {title: 'Second sub-sub level'},
                  {title: 'Third sub-sub level'}
                ]
              },
              {
                title: 'Second sub level',
                children: [
                  {title: 'First sub-sub level'},
                  {title: 'Second sub-sub level'},
                  {title: 'Third sub-sub level'}
                ]
              },
              {
                title: 'Third sub level',
                children: [
                  {title: 'First sub-sub level'},
                  {title: 'Second sub-sub level'},
                  {title: 'Third sub-sub level'}
                ]
              }
            ]
          },
          {
            title: 'Third top level',
            children: [
              {
                title: 'First sub level',
                children: [
                  {title: 'First sub-sub level'},
                  {title: 'Second sub-sub level'},
                  {title: 'Third sub-sub level'}
                ]
              },
              {
                title: 'Second sub level',
                children: [
                  {title: 'First sub-sub level'},
                  {title: 'Second sub-sub level'},
                  {title: 'Third sub-sub level'}
                ]
              },
              {
                title: 'Third sub level',
                children: [
                  {title: 'First sub-sub level'},
                  {title: 'Second sub-sub level'},
                  {title: 'Third sub-sub level'}
                ]
              }
            ]
          }
        ]
      }
    }
  }
</script>

<style scoped>

</style>

On gists

V-model in loops and computed

Vue.js

App.vue #

/* 
  https://stackblitz.com/edit/superlasice-efzixd?file=src%2FApp.vue 
*/

<template>
  <div id="app">
    <button v-on:click="add">add new row</button>
    <p>Total price {{ total }} | {{ total2 }}</p>

    <ul>
      <li v-for="(item, index) in items">
        Name<br />
        <input type="text" v-model="item.name" />
        <br />

        Quantity<br />
        <input type="number" v-model.number="item.quantity" min="1" />
        <br />

        Price<br />
        <input
          type="number"
          v-model.number="item.price"
          min="0.00"
          max="10000"
          step="1"
        />
        <br />

        Total (readonly) <br />
        <input v-model="totalItems[index]" readonly /> <br />

        total in row:
        {{ totalItem(item) }}
        <br />
        <br />

        <button v-on:click="remove(index)">Delete row</button>
        <hr />
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      items: [
        { name: 'A', quantity: 1, price: 20 },
        { name: 'B', quantity: 2, price: 30 },
      ],
    };
  },
  methods: {
    add() {
      this.items.push({
        name: 'New product',
        quantity: 0,
        price: 0,
      });
    },
    remove(index) {
      this.items.splice(index, 1);
    },
    totalItem(item) {
      return item.price * item.quantity;
    },
  },
  computed: {
    totalItems() {
      let arr = [];
      this.items.forEach((item) => {
        arr.push(parseFloat(item.price) * parseFloat(item.quantity));
      });

      return arr;
    },
    total() {
      let sum = 0;
      this.items.forEach((item) => {
        sum += parseFloat(item.price) * parseFloat(item.quantity);
      });

      return sum;
    },
    // another approach how to sum
    total2() {
      return this.items.reduce((prev, item) => {
        return prev + item.price * item.quantity;
      }, 0);
    },
  },
};
</script>

On gists

Abort exception

Nette Nette-Tricks

abort.php #

<?php


try
		{
		  // ...
			$this->redirect('PresenterWhatEver:default');

		}
		catch (\Exception $e)
		{
			// posle se to dal kdyz premserujeme - redirect vyhazuje abortException ...
			if ($e instanceof Nette\Application\AbortException)
			{
				throw $e;
			}
		}