# Rebilly Developer Coding Exemplar

## Instructions

This coding exemplar is designed to highlight your skills and areas of expertise with the Javascript and PHP language in general.

We rely on PHP as our backend language of choice and Javascript for our frontend language.
Because of this, it's important that developers have a well-rounded understanding of both PHP and Javascript languages.

> ***This exercise should take approximately one hour to complete.***


Good luck!

### Submit answers

Please complete the following questions to the best of your ability.
If you are unable to solve a question, please indicate as such.
You should feel free to use any online resources to solve these questions; after all, we expect that our developers will use their problem-solving skills at work!
Some questions are intended to be difficult, while others are meant to be easy or obvious.

> **Please post your answers in a [Gist](https://gist.github.com/), using Markdown format, and send the link for review.**


Don't send us neither direct nor rephrased responses for the quiz questions which are given by other experienced developers, including artificial intelligence (LLM such as ChatGPT).

## Question 1

During a large data migration, you get the following error: Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 54 bytes). You've traced the problem to the following snippet of code:


```php
$stmt = $pdo->prepare('SELECT * FROM largeTable');
$stmt->execute();
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($results as $result) {
  // manipulate the data here
}
```

Refactor this code so that it stops triggering a memory error.

## Question 2

Write a function that takes a phone number in any form and formats it using a delimiter supplied by the developer.
The delimiter is optional; if one is not supplied, use a dash (-).
Your function should accept a phone number in any format (e.g. 123-456-7890, (123) 456-7890, 1234567890, etc) and format it according to the 3-3-4 US block standard, using the delimiter specified.
Assume foreign phone numbers and country codes are out of scope.

Note: This question CAN be solved using a regular expression, but one is not REQUIRED as a solution.
Focus instead on cleanliness and effectiveness of the code, and take into account phone numbers that may not pass a sanity check.

Note: You may choose to answer in PHP or JavaScript or both.
How would your approach differ across languages?

## Question 3

Write a JavaScript function that would generate a hex color code (`#f1f2f3`) from the full name of a person.
It should always generate the same color for a given name.
Describe how you arrived at your solution.


```javascript
const name = 'John Doe';
const color = getColorFromName(name); // e.g. #9bc44c
```

## Question 4

Write a complete set of unit tests for **one** of the following code blocks.
Describe how the approach might change for the other language.

table
tr
td
 PHP 
td
 Javascript 
tr
td

```PHP
function fizzBuzz($start = 1, $stop = 100)
{
  $string = '';

  if($stop < $start || $start < 0 || $stop < 0) {
    throw new InvalidArgumentException;
  }

  for($i = $start; $i <= $stop; $i++) {
    if($i % 3 == 0 && $i % 5 == 0) {
      $string .= 'FizzBuzz';
      continue;
    }

    if($i % 3 == 0) {
      $string .= 'Fizz';
      continue;
    }

    if ($i % 5 == 0) {
      $string .= 'Buzz';
      continue;
    }

    $string .= $i;
  }

  return $string;
}
```

td

```javascript
function fizzBuzz(start = 1, stop = 100) {
  let result = '';

  if (stop < start || start < 0 || stop < 0) {
    throw new Error('Invalid arguments');
  }

  for (let i = start; i <= stop; i++) {
    if (i % 3 === 0 && i % 5 === 0) {
      result += 'FizzBuzz';
      continue;
    }

    if (i % 3 === 0) {
      result += 'Fizz';
      continue;
    }

    if (i % 5 === 0) {
      result += 'Buzz';
      continue;
    }

    result += i;
  }

  return result;
}
```

## Question 5

Refactor the following old TypeScript code. Don't go too deep, estimate up to 15 minutes of work.

Do not implement any libraries or frameworks.

The code shouldn't be ideal, rather adequate for the first step of the refactoring.
Feel free to leave comments in places which can be improved in the future if you see a possibility of that.


```typescript
const state: any = {
  items: JSON.parse(localStorage.getItem('items') || '[]'),
};
const root: any = document.getElementById('app');

const setState = (patch: any) => {
  state = {
    ...state,
    ...(typeof patch === 'function' ? patch(state) : patch),
  };
  localStorage.setItem('items', JSON.stringify(state.items));
  render();
};

function render() {
  root.innerHTML = '';
  const main = document.createElement('main');
  const list = state.items.reduce(
    (items: any, item: any) => `${items}
      <li id="${item.id}">
        ${((item && (item.title || item.text)) || '(untitled)').trim()}
        <button data-remove>✘</button>
      </li>`,
  );

  main.innerHTML = `<form>
    <input placeholder="Todo…" />
    <button type="submit">Add</button>
  </form>
  <ul>${list}</ul>`;

  const form = main.querySelector('form')!;
  function formSubmit(e: any) {
    e.preventDefault();
    const input = main.querySelector('input');
    const text = (input.value || '').trim();
    if (!text) return;
    setState((s: any) => ({
      items: [...s.items, { id: Date.now(), text }],
    }));
    input.value = '';
  }
  form.onsubmit = formSubmit;

  main.onclick = (e: any) => {
    const button = e.target;
    if (!button?.matches?.('[data-remove]')) return;
    const id = button.closest('li')?.getAttribute('id');
    setState((s: any) => ({
      items: s.items.filter((x: any) => x.id !== Number(id)),
    }));
  };

  root.appendChild(main);
}
render();
```

## Question 6

Refactor the following old legacy classes.

Don't go too deep, estimate up to 15 minutes of work.

The code shouldn't be ideal, rather adequate for the first step of the refactoring.
Feel free to leave comments in places which can be improved in the future if you see a possibility of that.


```php
<?php

class Document {

  public $user;

  public $name;

  public function init($name, User $user) {
    assert(strlen($name) > 5);
    $this->user = $user;
    $this->name = $name;
  }

  public function getTitle() {
    $db = Database::getInstance();
    $row = $db->query('SELECT * FROM document WHERE name = "' . $this->name . '" LIMIT 1');
    return $row[3]; // third column in a row
  }

  public static function getAllDocuments() {
    // to be implemented later
  }
}

class User {

  public function makeNewDocument($name) {
    if(!strpos(strtolower($name), 'senior')) {
      throw new Exception('The name should contain "senior"');
    }

    $doc = new Document();
    $doc->init($name, $this);
    return $doc;
  }

  public function getMyDocuments() {
    $list = array();
    foreach (Document::getAllDocuments() as $doc) {
      if ($doc->user == $this)
        $list[] = $doc;
    }
    return $list;
  }
}
```