Skip to content

Commit 3e583f3

Browse files
committed
feat: replace built-in pddikti with pluggable provider api
feat: add wastu.fyi provider
1 parent 0c33118 commit 3e583f3

12 files changed

Lines changed: 627 additions & 187 deletions

README.md

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Install the package with:
2424
composer require wastukancana/nim
2525
```
2626

27-
## Example
27+
## Usage
2828

2929
```php
3030
<?php
@@ -42,13 +42,60 @@ try {
4242
}
4343
```
4444

45+
Example dump without provider (name/gender/isGraduated null):
46+
47+
```php
48+
$student = (new Nim('211351143'))->dump();
49+
/* object(Wastukancana\Student) {
50+
nim: "211351143",
51+
name: null,
52+
gender: null,
53+
isGraduated: null,
54+
admissionYear: 2021,
55+
study: "Teknik Informatika",
56+
educationLevel: "S1",
57+
firstSemester: 1,
58+
sequenceNumber: 143
59+
} */
60+
```
61+
62+
### Provider (optional)
63+
64+
You can enrich student data by plugging one optional provider class (FQCN). Without a provider, only parser-derived fields are available (year, study, level, semester, sequence). Fields like name, gender, and graduation status will be null until a provider is used.
65+
66+
```php
67+
use Wastukancana\Nim;
68+
use Wastukancana\Provider\PDDikti;
69+
use Wastukancana\Provider\WastuFyi;
70+
71+
$nim = '211351143';
72+
73+
// Using PDDikti provider (pass FQCN)
74+
$student = (new Nim($nim, PDDikti::class))->dump();
75+
76+
// Using Wastu.FYI provider (requires a Bearer token)
77+
$token = getenv('WASTU_FYI_TOKEN');
78+
$student = (new Nim($nim, WastuFyi::class, ['token' => $token])))->dump();
79+
/* object(Wastukancana\Student) {
80+
nim: "211351143",
81+
name: "SULUH SULISTIAWAN",
82+
gender: "M",
83+
isGraduated: true,
84+
admissionYear: 2021,
85+
study: "Teknik Informatika",
86+
educationLevel: "S1",
87+
firstSemester: 1,
88+
sequenceNumber: 143
89+
} */
90+
```
91+
4592
## Development
4693

4794
Run code style checks and tests locally:
4895

4996
```bash
5097
composer psr2check
51-
php vendor/bin/phpunit --testdox tests
98+
composer tests
5299
```
53100

54101
This repository uses GitHub Actions to run the matrix CI against PHP 7.4 and 8.x with coverage reporting to Codecov.

composer.json

Lines changed: 44 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,48 @@
11
{
2-
"name": "wastukancana/nim",
3-
"type": "library",
4-
"description": "STT Wastukancana Student ID (NIM) Parser",
5-
"version": "1.2.1",
6-
"homepage": "https://github.com/sooluh/waska-nim",
7-
"license": "MIT",
8-
"authors": [
9-
{
10-
"name": "Abu Masyail",
11-
"email": "suluhs@aol.com",
12-
"homepage": "https://suluh.my.id",
13-
"role": "Maintainer"
14-
}
2+
"name": "wastukancana/nim",
3+
"type": "library",
4+
"description": "STT Wastukancana Student ID (NIM) Parser",
5+
"version": "1.2.1",
6+
"homepage": "https://github.com/sooluh/waska-nim",
7+
"license": "MIT",
8+
"authors": [
9+
{
10+
"name": "Abu Masyail",
11+
"email": "suluhs@aol.com",
12+
"homepage": "https://suluh.my.id",
13+
"role": "Maintainer"
14+
}
15+
],
16+
"support": {
17+
"source": "http://github.com/sooluh/waska-nim",
18+
"docs": "https://github.com/sooluh/waska-nim/blob/master/README.md",
19+
"issues": "https://github.com/sooluh/waska-nim/issues"
20+
},
21+
"scripts": {
22+
"psr2check": [
23+
"@php vendor/bin/phpcs --standard=PSR2 --ignore=tests/*,vendor/* ."
24+
],
25+
"psr2autofix": [
26+
"@php vendor/bin/phpcbf --standard=PSR2 --ignore=tests/*,vendor/* ."
1527
],
16-
"support": {
17-
"source": "http://github.com/sooluh/waska-nim",
18-
"docs": "https://github.com/sooluh/waska-nim/blob/master/README.md",
19-
"issues": "https://github.com/sooluh/waska-nim/issues"
20-
},
21-
"scripts": {
22-
"psr2check": [
23-
"@php vendor/bin/phpcs --standard=PSR2 --ignore=tests/*,vendor/* ."
24-
],
25-
"psr2autofix": [
26-
"@php vendor/bin/phpcbf --standard=PSR2 --ignore=tests/*,vendor/* ."
27-
],
28-
"tests": [
29-
"@php vendor/bin/phpunit --testdox tests",
30-
"@php vendor/bin/phpunit --coverage-html reports"
31-
]
32-
},
33-
"autoload": {
34-
"psr-4": {
35-
"Wastukancana\\": "src/"
36-
}
37-
},
38-
"require": {
39-
"php": "^7.4|^8.0",
40-
"guzzlehttp/guzzle": "^7.8"
41-
},
42-
"require-dev": {
43-
"squizlabs/php_codesniffer": "^3.7",
44-
"phpunit/phpunit": "^9.6",
45-
"mikey179/vfsstream": "^1.6"
28+
"tests": [
29+
"@php vendor/bin/phpunit --testdox tests",
30+
"@php vendor/bin/phpunit --coverage-html reports"
31+
]
32+
},
33+
"autoload": {
34+
"psr-4": {
35+
"Wastukancana\\": "src/"
4636
}
37+
},
38+
"require": {
39+
"php": "^7.4|^8.0",
40+
"guzzlehttp/guzzle": "^7.8",
41+
"laravel/pint": "^1.25"
42+
},
43+
"require-dev": {
44+
"squizlabs/php_codesniffer": "^3.7",
45+
"phpunit/phpunit": "^9.6",
46+
"mikey179/vfsstream": "^1.6"
47+
}
4748
}

example.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
<?php
22

33
use Wastukancana\Nim;
4+
use Wastukancana\Provider\PDDikti;
45

56
require __DIR__.'/vendor/autoload.php';
67

78
try {
8-
$nim = new Nim('91151001');
9+
$nim = new Nim('91151001', PDDikti::class);
910

1011
var_dump($nim->dump());
1112
} catch (\Exception $e) {

src/Nim.php

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,24 @@ class Nim extends Parser
88
{
99
private const MIN_YEAR = 2001;
1010

11-
private PDDikti $pddikti;
11+
private ?StudentProviderInterface $provider = null;
1212

13-
public function __construct($nim)
13+
public function __construct($nim, ?string $provider = null, array $options = [])
1414
{
1515
parent::__construct($nim);
1616

1717
$this->isValid();
18-
$this->pddikti = new PDDikti($this->nim);
18+
19+
if (is_string($provider)
20+
&& class_exists($provider)
21+
&& is_subclass_of($provider, StudentProviderInterface::class)
22+
) {
23+
if (array_key_exists('token', $options)) {
24+
$this->provider = new $provider($this->nim, $options['token']);
25+
} else {
26+
$this->provider = new $provider($this->nim);
27+
}
28+
}
1929
}
2030

2131
private function isValid(): bool
@@ -41,17 +51,17 @@ private function isValid(): bool
4151

4252
public function getName()
4353
{
44-
return $this->pddikti->getName();
54+
return $this->provider ? $this->provider->getName() : null;
4555
}
4656

4757
public function getGender()
4858
{
49-
return $this->pddikti->getGender();
59+
return $this->provider ? $this->provider->getGender() : null;
5060
}
5161

5262
public function getIsGraduated()
5363
{
54-
return $this->pddikti->getIsGraduated();
64+
return $this->provider ? $this->provider->getIsGraduated() : null;
5565
}
5666

5767
public function isValidAdmissionYear(): bool
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
<?php
22

3-
namespace Wastukancana;
3+
namespace Wastukancana\Provider;
44

55
use Exception;
66
use GuzzleHttp\Client;
77
use Psr\Http\Message\ResponseInterface;
8+
use Wastukancana\StudentProviderInterface;
89

9-
class PDDikti
10+
class PDDikti implements StudentProviderInterface
1011
{
1112
private Client $http;
1213

@@ -20,9 +21,9 @@ class PDDikti
2021

2122
private ?bool $isGraduated = null;
2223

23-
public function __construct(string $nim)
24+
public function __construct(string $nim, ?Client $client = null)
2425
{
25-
$this->http = new Client([
26+
$this->http = $client ?? new Client([
2627
'base_uri' => 'https://api-pddikti.kemdiktisaintek.go.id',
2728
'verify' => false,
2829
]);

src/Provider/WastuFyi.php

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<?php
2+
3+
namespace Wastukancana\Provider;
4+
5+
use Exception;
6+
use GuzzleHttp\Client;
7+
use Psr\Http\Message\ResponseInterface;
8+
use Wastukancana\StudentProviderInterface;
9+
10+
class WastuFyi implements StudentProviderInterface
11+
{
12+
private Client $http;
13+
14+
private string $nim;
15+
16+
private ?string $name = null;
17+
18+
private ?string $gender = null;
19+
20+
private ?bool $isGraduated = null;
21+
22+
public function __construct(string $nim, string $bearerToken, ?Client $client = null)
23+
{
24+
$this->http = $client ?? new Client([
25+
'base_uri' => 'https://api.wastu.fyi',
26+
'verify' => false,
27+
'headers' => ['Authorization' => 'Bearer '.$bearerToken],
28+
]);
29+
$this->nim = ltrim($nim, '0');
30+
}
31+
32+
private function fetchData(string $endpoint): ?object
33+
{
34+
try {
35+
$response = $this->http->request('GET', $endpoint);
36+
37+
return $this->parseResponse($response);
38+
} catch (Exception $e) {
39+
return null;
40+
}
41+
}
42+
43+
private function parseResponse(ResponseInterface $response): ?object
44+
{
45+
$content = $response->getBody()->getContents();
46+
47+
return json_decode($content);
48+
}
49+
50+
private function prepare(): void
51+
{
52+
if ($this->name !== null || $this->gender !== null || $this->isGraduated !== null) {
53+
return;
54+
}
55+
56+
$response = $this->fetchData('students/detail?student_id='.$this->nim);
57+
58+
if (! $response) {
59+
return;
60+
}
61+
62+
$data = $response->data ?? null;
63+
64+
if (! $data) {
65+
return;
66+
}
67+
68+
$status = isset($data->status) ? strtolower((string) $data->status) : null;
69+
70+
$this->name = $data->name ?? null;
71+
$this->gender = $data->gender ?? null;
72+
$this->isGraduated = $status !== null ? ($status === 'lulus') : null;
73+
}
74+
75+
public function getName(): ?string
76+
{
77+
$this->prepare();
78+
79+
return $this->name;
80+
}
81+
82+
public function getGender(): ?string
83+
{
84+
$this->prepare();
85+
86+
return $this->gender;
87+
}
88+
89+
public function getIsGraduated(): ?bool
90+
{
91+
$this->prepare();
92+
93+
return $this->isGraduated;
94+
}
95+
}

src/Student.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,20 @@
55
class Student
66
{
77
public string $nim;
8+
89
public ?string $name = null;
10+
911
public ?string $gender = null;
12+
1013
public ?bool $isGraduated = null;
1114

1215
public int $admissionYear;
16+
1317
public string $study;
18+
1419
public string $educationLevel;
20+
1521
public int $firstSemester;
22+
1623
public int $sequenceNumber;
1724
}

src/StudentProviderInterface.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
namespace Wastukancana;
4+
5+
interface StudentProviderInterface
6+
{
7+
public function getName(): ?string;
8+
9+
public function getGender(): ?string;
10+
11+
public function getIsGraduated(): ?bool;
12+
}

0 commit comments

Comments
 (0)