update
parent
26c8e7df99
commit
7a3b57d600
46
.env
46
.env
|
@ -1,46 +0,0 @@
|
||||||
APP_NAME=Laravel
|
|
||||||
APP_ENV=local
|
|
||||||
APP_KEY=base64:kJqxmAbo0WxiIy/a1U0U807qcfgj+Dz7ZVrQHZaiJ84=
|
|
||||||
APP_DEBUG=true
|
|
||||||
APP_URL=http://localhost
|
|
||||||
|
|
||||||
LOG_CHANNEL=stack
|
|
||||||
|
|
||||||
DB_CONNECTION=pgsql
|
|
||||||
DB_HOST=localhost
|
|
||||||
DB_PORT=5432
|
|
||||||
DB_DATABASE=dikplhd
|
|
||||||
DB_USERNAME=postgres
|
|
||||||
DB_PASSWORD=postgres
|
|
||||||
|
|
||||||
BROADCAST_DRIVER=log
|
|
||||||
CACHE_DRIVER=file
|
|
||||||
QUEUE_CONNECTION=sync
|
|
||||||
SESSION_DRIVER=file
|
|
||||||
SESSION_LIFETIME=120
|
|
||||||
|
|
||||||
REDIS_HOST=127.0.0.1
|
|
||||||
REDIS_PASSWORD=null
|
|
||||||
REDIS_PORT=6379
|
|
||||||
|
|
||||||
MAIL_MAILER=smtp
|
|
||||||
MAIL_HOST=smtp.mailtrap.io
|
|
||||||
MAIL_PORT=2525
|
|
||||||
MAIL_USERNAME=null
|
|
||||||
MAIL_PASSWORD=null
|
|
||||||
MAIL_ENCRYPTION=null
|
|
||||||
MAIL_FROM_ADDRESS=null
|
|
||||||
MAIL_FROM_NAME="${APP_NAME}"
|
|
||||||
|
|
||||||
AWS_ACCESS_KEY_ID=
|
|
||||||
AWS_SECRET_ACCESS_KEY=
|
|
||||||
AWS_DEFAULT_REGION=us-east-1
|
|
||||||
AWS_BUCKET=
|
|
||||||
|
|
||||||
PUSHER_APP_ID=
|
|
||||||
PUSHER_APP_KEY=
|
|
||||||
PUSHER_APP_SECRET=
|
|
||||||
PUSHER_APP_CLUSTER=mt1
|
|
||||||
|
|
||||||
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
|
||||||
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
.env
|
||||||
|
public/uploads
|
||||||
|
vendor
|
|
@ -36,49 +36,8 @@ class DatasetController extends Controller
|
||||||
return view($this->template.'.index',$data);
|
return view($this->template.'.index',$data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function grid(Request $request)
|
public function gridDetail(Request $request)
|
||||||
{
|
{
|
||||||
|
|
||||||
// $data = Dataset::all();
|
|
||||||
// // $data = User::with(['group'])->orderBy('id','DESC')->get();
|
|
||||||
// $_data = [];
|
|
||||||
|
|
||||||
|
|
||||||
// foreach ($data as $key => $row) {
|
|
||||||
|
|
||||||
|
|
||||||
// $action = '';
|
|
||||||
|
|
||||||
// if((permission('is_create', $this->route.'.*','module',false)) || (permission('is_update', $this->route.'.*','module',false))){
|
|
||||||
// $action .= '<div class="flex gap-3 justify-center items-center flex-row">';
|
|
||||||
// $action .= '<a href="'.url('opendata/dataset/update/'.encode_id($row->DatasetId)).'" data-toggle="tooltip" title="Ubah Data" class="btn btn-sm btn-block bg-primary"><i class="ri-pencil-line text-white"></i></a>';
|
|
||||||
// $action .= '<a href="'.url('opendata/dataset/view/'.encode_id($row->DatasetId)).'" data-toggle="tooltip" title="Lihat Data" class="btn btn-sm btn-block bg-info"><i class="ri-eye-line text-white"></i></a>';
|
|
||||||
// if(session('group_id') == 1){
|
|
||||||
// // $action .= '<a href="#" data-href="'.url('management/user/forcelogin/'.encode_id($row->id)).'" data-toggle="tooltip" title="Force Login" class="forcelogin btn btn-sm btn-block bg-success"><i class="ri-user-2-line text-white"></i></a>';
|
|
||||||
// // $action .= '<a href="#" data-href="'.url('management/user/delete/'.encode_id($row->id)).'" data-toggle="tooltip" title="Hapus Data" class="remove_data btn btn-sm btn-block bg-danger"><i class="ri-delete-bin-line text-white"></i></a>';
|
|
||||||
// }
|
|
||||||
// $action .= '</div>';
|
|
||||||
// }
|
|
||||||
|
|
||||||
// $_data[] = [
|
|
||||||
// 'no' => $key+1,
|
|
||||||
// 'id' => encode_id($row->id),
|
|
||||||
// 'name' => @$row->name,
|
|
||||||
// 'publik' => @$row->publik,
|
|
||||||
// 'created_at' => date('d-m-Y H:i:s',strtotime(@$row->created_at)),
|
|
||||||
// 'instansi' => @$row->instansi->name,
|
|
||||||
// 'action' => @$action,
|
|
||||||
// ];
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // return response()->json($_data); // Return the data as a JSON response
|
|
||||||
// return response()->json($_data);
|
|
||||||
|
|
||||||
// $perPage = $request->query('limit', 10);
|
|
||||||
// $page = $request->query('page', 1);
|
|
||||||
// // dd($page);
|
|
||||||
// $search = $request->query('search');
|
|
||||||
$id = $request->query('id');
|
$id = $request->query('id');
|
||||||
$keyId = decode_id($id);
|
$keyId = decode_id($id);
|
||||||
$item = Dataset::find($keyId); // atau pakai ->pluck(), ->find(), dll
|
$item = Dataset::find($keyId); // atau pakai ->pluck(), ->find(), dll
|
||||||
|
@ -93,31 +52,46 @@ class DatasetController extends Controller
|
||||||
'rows' => $rows
|
'rows' => $rows
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// // Ambil JSON dari kolom database
|
}
|
||||||
// $rawData = Dataset::find($keyId)->data; // atau pakai ->pluck(), ->find(), dll
|
|
||||||
// $array = json_decode($rawData, true); // array dari JSON
|
|
||||||
// $collection = collect($array);
|
|
||||||
|
|
||||||
// if ($search) {
|
public function grid(Request $request)
|
||||||
// $collection = $collection->filter(function ($item) use ($search) {
|
{
|
||||||
// foreach ($item as $value) {
|
|
||||||
// if (stripos($value, $search) !== false) {
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return false;
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// $total = $collection->count();
|
$data = Dataset::all();
|
||||||
|
// $data = User::with(['group'])->orderBy('id','DESC')->get();
|
||||||
|
$_data = [];
|
||||||
|
|
||||||
// $paginated = $collection->slice(($page - 1) * $perPage, $perPage)->values();
|
|
||||||
|
|
||||||
// return response()->json([
|
foreach ($data as $key => $row) {
|
||||||
// 'data' => $paginated,
|
|
||||||
// 'page' => $page,
|
|
||||||
// 'total' => $total
|
$action = '';
|
||||||
// ]);
|
|
||||||
|
if((permission('is_create', $this->route.'.*','module',false)) || (permission('is_update', $this->route.'.*','module',false))){
|
||||||
|
$action .= '<div class="flex gap-3 justify-center items-center flex-row">';
|
||||||
|
$action .= '<a href="'.url('opendata/dataset/update/'.encode_id($row->DatasetId)).'" data-toggle="tooltip" title="Ubah Data" class="btn btn-sm btn-block bg-primary"><i class="ri-pencil-line text-white"></i></a>';
|
||||||
|
$action .= '<a href="'.url('opendata/dataset/view/'.encode_id($row->DatasetId)).'" data-toggle="tooltip" title="Lihat Data" class="btn btn-sm btn-block bg-info"><i class="ri-eye-line text-white"></i></a>';
|
||||||
|
if(session('group_id') == 1){
|
||||||
|
// $action .= '<a href="#" data-href="'.url('management/user/forcelogin/'.encode_id($row->id)).'" data-toggle="tooltip" title="Force Login" class="forcelogin btn btn-sm btn-block bg-success"><i class="ri-user-2-line text-white"></i></a>';
|
||||||
|
// $action .= '<a href="#" data-href="'.url('management/user/delete/'.encode_id($row->id)).'" data-toggle="tooltip" title="Hapus Data" class="remove_data btn btn-sm btn-block bg-danger"><i class="ri-delete-bin-line text-white"></i></a>';
|
||||||
|
}
|
||||||
|
$action .= '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$_data[] = [
|
||||||
|
'no' => $key+1,
|
||||||
|
'id' => encode_id($row->id),
|
||||||
|
'name' => @$row->name,
|
||||||
|
'publik' => @$row->publik,
|
||||||
|
'created_at' => date('d-m-Y H:i:s',strtotime(@$row->created_at)),
|
||||||
|
'instansi' => @$row->instansi->name,
|
||||||
|
'action' => @$action,
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// return response()->json($_data); // Return the data as a JSON response
|
||||||
|
return response()->json($_data);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,90 +108,101 @@ class DatasetController extends Controller
|
||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
Validator::make($request->all(), [
|
// dd(request()->all());
|
||||||
'name' => 'required',
|
|
||||||
'instansi_id' => 'required',
|
|
||||||
'template_id' => 'required',
|
|
||||||
'template_default' => 'required',
|
|
||||||
'publik' => 'required',
|
|
||||||
'tags' => 'required',
|
|
||||||
'file' => 'required|file|mimes:xlsx,xls',
|
|
||||||
'topik' => 'required',
|
|
||||||
])->validate();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$keyId = decode_id($request->secure_id);
|
$keyId = decode_id($request->secure_id);
|
||||||
|
|
||||||
$file = $request->file('file');
|
|
||||||
$path = $file->getRealPath();
|
|
||||||
$spreadsheet = IOFactory::load($path);
|
|
||||||
$sheet = $spreadsheet->getActiveSheet();
|
|
||||||
$rows = $sheet->toArray();
|
|
||||||
$header = $rows[0]; // Baris pertama sebagai header
|
|
||||||
$data = [];
|
$data = [];
|
||||||
|
$filePath = null;
|
||||||
|
if(@$request->file){
|
||||||
|
$file = $request->file('file');
|
||||||
|
$path = $file->getRealPath();
|
||||||
|
$spreadsheet = IOFactory::load($path);
|
||||||
|
$sheet = $spreadsheet->getActiveSheet();
|
||||||
|
$rows = $sheet->toArray();
|
||||||
|
$header = $rows[0]; // Baris pertama sebagai header
|
||||||
|
if (@$request->hasFile('file')) {
|
||||||
|
$file = $request->file('file');
|
||||||
|
$destinationPath = public_path('uploads/dataset');
|
||||||
|
$current = Carbon::now()->format('Y/m/d');
|
||||||
|
$path = $destinationPath . '/' . $current;
|
||||||
|
$fileName = $file->getClientOriginalName();
|
||||||
|
$fileMime = $file->getClientMimeType();
|
||||||
|
$fileExtension = $file->getClientOriginalExtension();
|
||||||
|
$fileSize = $file->getSize();
|
||||||
|
if(($fileExtension != 'xls') && ($fileExtension != 'xlsx')){
|
||||||
|
return redirect()->back()->with([
|
||||||
|
'message' => 'Maaf File Harus Berupa xls,xlsx!',
|
||||||
|
'type' => "error"
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$newFilename = session('id').'_'.uniqid('file_') . '.' . $fileExtension;
|
||||||
|
|
||||||
if (@$request->hasFile('file')) {
|
if (!File::exists($path)) {
|
||||||
$file = $request->file('file');
|
File::isDirectory($path) or File::makeDirectory($path, 0777, true, true);
|
||||||
$destinationPath = public_path('uploads/dataset');
|
|
||||||
$current = Carbon::now()->format('Y/m/d');
|
|
||||||
$path = $destinationPath . '/' . $current;
|
|
||||||
$fileName = $file->getClientOriginalName();
|
|
||||||
$fileMime = $file->getClientMimeType();
|
|
||||||
$fileExtension = $file->getClientOriginalExtension();
|
|
||||||
$fileSize = $file->getSize();
|
|
||||||
if(($fileExtension != 'xls') && ($fileExtension != 'xlsx')){
|
|
||||||
return redirect()->back()->with([
|
|
||||||
'message' => 'Maaf File Harus Berupa xls,xlsx!',
|
|
||||||
'type' => "error"
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
$newFilename = session('id').'_'.uniqid('file_') . '.' . $fileExtension;
|
|
||||||
|
|
||||||
if (!File::exists($path)) {
|
|
||||||
File::isDirectory($path) or File::makeDirectory($path, 0777, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$filePath = 'dataset/' . $current . '/' . $newFilename;
|
|
||||||
$uploaded = $file->move($path, $newFilename);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for ($i = 1; $i < count($rows); $i++) {
|
|
||||||
$row = $rows[$i];
|
|
||||||
|
|
||||||
// Skip baris kosong
|
|
||||||
if (collect($row)->filter()->isEmpty()) continue;
|
|
||||||
|
|
||||||
$assoc = [];
|
|
||||||
foreach ($header as $j => $columnName) {
|
|
||||||
if($columnName != null){
|
|
||||||
$assoc[strtolower(str_replace(' ','_',$columnName))] = $row[$j] ?? null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$data[] = $assoc;
|
$filePath = 'dataset/' . $current . '/' . $newFilename;
|
||||||
}
|
$uploaded = $file->move($path, $newFilename);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for ($i = 1; $i < count($rows); $i++) {
|
||||||
|
$row = $rows[$i];
|
||||||
|
|
||||||
|
// Skip baris kosong
|
||||||
|
if (collect($row)->filter()->isEmpty()) continue;
|
||||||
|
|
||||||
|
$assoc = [];
|
||||||
|
foreach ($header as $j => $columnName) {
|
||||||
|
if($columnName != null){
|
||||||
|
$assoc[strtolower(str_replace(' ','_',$columnName))] = $row[$j] ?? null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$data[] = $assoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(@$keyId){
|
if(@$keyId){
|
||||||
|
Validator::make($request->all(), [
|
||||||
|
'name' => 'required',
|
||||||
|
'instansi_id' => 'required',
|
||||||
|
'template_id' => 'required',
|
||||||
|
// 'template_default' => 'required',
|
||||||
|
'publik' => 'required',
|
||||||
|
'tags' => 'required',
|
||||||
|
'topik' => 'required',
|
||||||
|
])->validate();
|
||||||
|
|
||||||
$insert = Dataset::find($keyId);
|
$insert = Dataset::find($keyId);
|
||||||
$insert->instansi_id = decode_id($request->instansi_id);
|
$insert->instansi_id = decode_id($request->instansi_id);
|
||||||
$insert->template_id = decode_id($request->template_id);
|
$insert->template_id = decode_id($request->template_id);
|
||||||
$insert->template_default = $request->template_default;
|
// $insert->template_default = $request->template_default;
|
||||||
$insert->name = $request->name;
|
$insert->name = $request->name;
|
||||||
$insert->publik = $request->publik;
|
$insert->publik = $request->publik;
|
||||||
$insert->tags = json_encode($request->tags);
|
$insert->tags = json_encode($request->tags);
|
||||||
$insert->data = json_encode($data);
|
if(@$request->hasFile('file')){
|
||||||
$insert->file = $filePath;
|
$insert->data = json_encode($data);
|
||||||
|
$insert->file = $filePath;
|
||||||
|
}
|
||||||
$insert->topik = json_encode($request->topik);
|
$insert->topik = json_encode($request->topik);
|
||||||
$insert->deskripsi = $request->deskripsi;
|
$insert->deskripsi = $request->deskripsi;
|
||||||
$insert->created_by = auth()->user()->id;
|
|
||||||
$insert->save();
|
$insert->save();
|
||||||
}else{
|
}else{
|
||||||
|
Validator::make($request->all(), [
|
||||||
|
'name' => 'required',
|
||||||
|
'instansi_id' => 'required',
|
||||||
|
'template_id' => 'required',
|
||||||
|
'template_default' => 'required',
|
||||||
|
'publik' => 'required',
|
||||||
|
'tags' => 'required',
|
||||||
|
'file' => 'required|file|mimes:xlsx,xls',
|
||||||
|
'topik' => 'required',
|
||||||
|
])->validate();
|
||||||
|
|
||||||
$insert = new Dataset;
|
$insert = new Dataset;
|
||||||
$insert->instansi_id = decode_id($request->instansi_id);
|
$insert->instansi_id = decode_id($request->instansi_id);
|
||||||
$insert->template_id = decode_id($request->template_id);
|
$insert->template_id = decode_id($request->template_id);
|
||||||
|
@ -275,7 +260,7 @@ class DatasetController extends Controller
|
||||||
$data['title'] = $this->title;
|
$data['title'] = $this->title;
|
||||||
$data['route'] = $this->route;
|
$data['route'] = $this->route;
|
||||||
$data['keyId'] = $id;
|
$data['keyId'] = $id;
|
||||||
$data['item'] = null;
|
$data['item'] = Dataset::find($keyId);
|
||||||
$data['instansi'] = Instansi::all();
|
$data['instansi'] = Instansi::all();
|
||||||
$data['topik'] = Topik::all();
|
$data['topik'] = Topik::all();
|
||||||
$data['template'] = Template::all();
|
$data['template'] = Template::all();
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -8,7 +8,7 @@
|
||||||
<img src="https://lingkunganhidup.jakarta.go.id/dist/images/logo/logo-dlh-big.png" class="" alt="Light logo" width="35">
|
<img src="https://lingkunganhidup.jakarta.go.id/dist/images/logo/logo-dlh-big.png" class="" alt="Light logo" width="35">
|
||||||
</div>
|
</div>
|
||||||
<div class="flex text-menu flex-col gap-1">
|
<div class="flex text-menu flex-col gap-1">
|
||||||
<h6 class="text-white text-lg">DIKPLHD</h6>
|
<h6 class="text-white text-lg bold">DIKPLHD</h6>
|
||||||
<h6 class="text-white text-xs">Dinas Lingkungan Hidup</h6>
|
<h6 class="text-white text-xs">Dinas Lingkungan Hidup</h6>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
<select name="instansi_id" required class="form-input instansi_id select2 @error('instansi_id') is-invalid @enderror" id="">
|
<select name="instansi_id" required class="form-input instansi_id select2 @error('instansi_id') is-invalid @enderror" id="">
|
||||||
<option value="">-</option>
|
<option value="">-</option>
|
||||||
@foreach($instansi as $dataInstansi)
|
@foreach($instansi as $dataInstansi)
|
||||||
<option value="{{encode_id($dataInstansi->MsInstansiId)}}">{{$dataInstansi->name}}</option>
|
<option {{@$item->instansi_id == $dataInstansi->MsInstansiId ? 'selected' : ''}} value="{{encode_id($dataInstansi->MsInstansiId)}}">{{$dataInstansi->name}}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
@error('instansi_id')
|
@error('instansi_id')
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
<select name="template_id" required class="form-input template_id select2 @error('template_id') is-invalid @enderror" id="">
|
<select name="template_id" required class="form-input template_id select2 @error('template_id') is-invalid @enderror" id="">
|
||||||
<option value="">-</option>
|
<option value="">-</option>
|
||||||
@foreach($template as $dataTemplate)
|
@foreach($template as $dataTemplate)
|
||||||
<option value="{{encode_id($dataTemplate->MsTemplateId)}}">{{$dataTemplate->name}}</option>
|
<option {{@$item->template_id == $dataTemplate->MsTemplateId ? 'selected' : ''}} data-template="{{asset($dataTemplate->template_url)}}" value="{{encode_id($dataTemplate->MsTemplateId)}}">{{$dataTemplate->name}}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
@error('template_id')
|
@error('template_id')
|
||||||
|
@ -43,10 +43,10 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="mb-3 required">Apakah Menggunakan Template Yang Disediakan ?</label>
|
<label class="mb-3 required">Apakah Menggunakan Template Yang Disediakan ?</label>
|
||||||
<select name="template_default" class="form-input @error('template_default') is-invalid @enderror" id="template_default" required>
|
<select name="template_default" {{@$item->template_default ? 'disabled' : 'required'}} class="form-input {{@$item->template_default ? 'bg-secondary/50 text-white' : ''}} @error('template_default') is-invalid @enderror" id="template_default">
|
||||||
<option value="">-</option>
|
<option value="">-</option>
|
||||||
<option value="1">Ya</option>
|
<option {{@$item->template_default == 1 ? 'selected' : ''}} value="1">Ya</option>
|
||||||
<option value="0">Tidak</option>
|
<option {{@$item->template_default == 0 ? 'selected' : ''}} value="0">Tidak</option>
|
||||||
</select>
|
</select>
|
||||||
@error('template_default')
|
@error('template_default')
|
||||||
<span class="invalid-feedback" style="display: block!important;"><strong>{{$message}}</strong></span>
|
<span class="invalid-feedback" style="display: block!important;"><strong>{{$message}}</strong></span>
|
||||||
|
@ -69,8 +69,8 @@
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="mb-3 required">Sifat Dataset</label>
|
<label class="mb-3 required">Sifat Dataset</label>
|
||||||
<select name="publik" required class="form-input @error('publik') is-invalid @enderror" id="">
|
<select name="publik" required class="form-input @error('publik') is-invalid @enderror" id="">
|
||||||
<option value="1">Terbuka/Publik</option>
|
<option {{@$item->publik == 1 ? 'selected' : ''}} value="1">Terbuka/Publik</option>
|
||||||
<option value="0">Rahasia/Private</option>
|
<option {{@$item->publik == 0 ? 'selected' : ''}} value="0">Rahasia/Private</option>
|
||||||
</select>
|
</select>
|
||||||
@error('publik')
|
@error('publik')
|
||||||
<span class="invalid-feedback" style="display: block!important;"><strong>{{$message}}</strong></span>
|
<span class="invalid-feedback" style="display: block!important;"><strong>{{$message}}</strong></span>
|
||||||
|
@ -79,7 +79,17 @@
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="mb-3 required">Tags / Kata Kunci</label>
|
<label class="mb-3 required">Tags / Kata Kunci</label>
|
||||||
<div id="tag-container" class="flex flex-wrap gap-2 p-2 form-input rounded bg-white focus-within:ring-2 ring-blue-500">
|
<div id="tag-container" class="flex flex-wrap gap-2 p-2 form-input rounded bg-white focus-within:ring-2 ring-blue-500">
|
||||||
<input id="tag-input" type="text" value="{{@$item->tags ? @$item->tags : old('tags')}}" name="tags[]" placeholder="Tambah tag..." class="flex-grow border-none p-1 text-sm" />
|
<?php
|
||||||
|
$tag = @json_decode(@$item->tags);
|
||||||
|
?>
|
||||||
|
@if(@$tag)
|
||||||
|
@foreach($tag as $dataTags)
|
||||||
|
@if(@$dataTags)
|
||||||
|
<span class="inline-flex items-center px-2 py-1 bg-primary text-white text-sm rounded">{{@$dataTags}} <button type="button" class="ml-1 text-blue-500 hover:text-red-600">×</button><input type="hidden" name="tags[]" value="{{@$dataTags}}"></span>
|
||||||
|
@endif
|
||||||
|
@endforeach
|
||||||
|
@endif
|
||||||
|
<input id="tag-input" type="text" value="" name="tags[]" placeholder="Tambah tag..." class="flex-grow border-none p-1 text-sm" />
|
||||||
</div>
|
</div>
|
||||||
<small><i>*Sesuaikan kata kunci dengan dataset Anda</i></small>
|
<small><i>*Sesuaikan kata kunci dengan dataset Anda</i></small>
|
||||||
@error('tags')
|
@error('tags')
|
||||||
|
@ -89,8 +99,12 @@
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="mb-3 required">Upload File</label>
|
<label class="mb-3 required">Upload File</label>
|
||||||
<input type="file" accept=".xls,.xlsx" value="{{@$item->file ? @$item->file : old('file')}}" name="file" class="form-input @error('file') is-invalid @enderror" placeholder="Masukan File Dataset" required>
|
<input type="file" accept=".xls,.xlsx" value="{{@$item->file ? @$item->file : old('file')}}" name="file" class="form-input @error('file') is-invalid @enderror" placeholder="Masukan File Dataset" {{@$item->file ? '' : 'required'}}>
|
||||||
<small><i>Masukan Ekstensi File : .xls,.xlsx</i></small>
|
<small><i>Masukan Ekstensi File : .xls,.xlsx</i></small>
|
||||||
|
@if(@$item->file)
|
||||||
|
<br>
|
||||||
|
<a href="{{asset('uploads/'.$item->file)}}" class="btn bg-success text-white mt-3"><i class="ri-download-line"></i> Download File</a>
|
||||||
|
@endif
|
||||||
@error('file')
|
@error('file')
|
||||||
<span class="invalid-feedback" style="display: block!important;"><strong>{{$message}}</strong></span>
|
<span class="invalid-feedback" style="display: block!important;"><strong>{{$message}}</strong></span>
|
||||||
@enderror
|
@enderror
|
||||||
|
@ -100,7 +114,12 @@
|
||||||
<label class="mb-3 required">Topik</label>
|
<label class="mb-3 required">Topik</label>
|
||||||
<select required name="topik[]" class="form-input select2 @error('topik') is-invalid @enderror" multiple>
|
<select required name="topik[]" class="form-input select2 @error('topik') is-invalid @enderror" multiple>
|
||||||
@foreach($topik as $dataTopik)
|
@foreach($topik as $dataTopik)
|
||||||
<option value="{{encode_id($dataTopik->MsTopikId)}}">{{$dataTopik->name}}</option>
|
@php
|
||||||
|
if(@$item){
|
||||||
|
$isSelected = is_array(json_decode($item->topik) ?? []) && in_array(encode_id($dataTopik->MsTopikId), json_decode($item->topik));
|
||||||
|
}
|
||||||
|
@endphp
|
||||||
|
<option {{ @$isSelected ? 'selected' : '' }} value="{{encode_id($dataTopik->MsTopikId)}}">{{$dataTopik->name}}</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
</select>
|
</select>
|
||||||
@error('topik')
|
@error('topik')
|
||||||
|
@ -110,7 +129,7 @@
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="mb-3 required">Deskripsi Dataset</label>
|
<label class="mb-3 required">Deskripsi Dataset</label>
|
||||||
<textarea name="deskripsi" required class="form-input @error('deskripsi') is-invalid @enderror" id="">{{@$item->deskripsi}}</textarea>
|
<textarea name="deskripsi" rows="10" required class="form-input @error('deskripsi') is-invalid @enderror" id="">{{@$item->deskripsi}}</textarea>
|
||||||
@error('deskripsi')
|
@error('deskripsi')
|
||||||
<span class="invalid-feedback" style="display: block!important;"><strong>{{$message}}</strong></span>
|
<span class="invalid-feedback" style="display: block!important;"><strong>{{$message}}</strong></span>
|
||||||
@enderror
|
@enderror
|
||||||
|
@ -126,6 +145,7 @@
|
||||||
@endsection
|
@endsection
|
||||||
@section('js')
|
@section('js')
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
const input = document.getElementById('tag-input');
|
const input = document.getElementById('tag-input');
|
||||||
const container = document.getElementById('tag-container');
|
const container = document.getElementById('tag-container');
|
||||||
|
|
||||||
|
@ -160,15 +180,20 @@
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
$('.template_id').on('change',function(){
|
||||||
|
var template = $(this).find(':selected').attr('data-template');
|
||||||
|
$('.btnDownload').attr('href',template);
|
||||||
|
});
|
||||||
$('#template_default').on('change',function(){
|
$('#template_default').on('change',function(){
|
||||||
var instansi_id = $('.instansi_id').find(':selected').val();
|
var instansi_id = $('.instansi_id').find(':selected').val();
|
||||||
var val = $(this).find(':selected').val();
|
var val = $(this).find(':selected').val();
|
||||||
|
var template = $('.template_id').find(':selected').attr('data-template');
|
||||||
if(instansi_id == ''){
|
if(instansi_id == ''){
|
||||||
toastr.error("Data instansi_id Belum Dipilih", 'Error!', {positionClass: 'toast-bottom-right', containerId: 'toast-bottom-right'});
|
toastr.error("Data instansi_id Belum Dipilih", 'Error!', {positionClass: 'toast-bottom-right', containerId: 'toast-bottom-right'});
|
||||||
$('#template_default').val('');
|
$('#template_default').val('');
|
||||||
}else{
|
}else{
|
||||||
if(val == 1){
|
if(val == 1){
|
||||||
$('.btnDownload').attr('href',"{{url('test')}}");
|
$('.btnDownload').attr('href',template);
|
||||||
$('.btnDownload').removeClass('hidden');
|
$('.btnDownload').removeClass('hidden');
|
||||||
}else{
|
}else{
|
||||||
$('.btnDownload').attr('href',"#");
|
$('.btnDownload').attr('href',"#");
|
||||||
|
|
|
@ -56,14 +56,16 @@
|
||||||
<?php
|
<?php
|
||||||
$data = json_decode($item->data);
|
$data = json_decode($item->data);
|
||||||
?>
|
?>
|
||||||
<!-- <div id="table-grid"></div> -->
|
|
||||||
|
<div style="overflow-x:auto;">
|
||||||
|
|
||||||
<table id="table"
|
<table id="table"
|
||||||
data-toggle="table"
|
data-toggle="table"
|
||||||
data-search="false"
|
data-search="false"
|
||||||
data-pagination="true"
|
data-pagination="true"
|
||||||
data-side-pagination="server"
|
data-side-pagination="server"
|
||||||
data-url="{{ route($route.'.grid', ['id' => $keyId]) }}">
|
data-url="{{ route($route.'.gridDetail', ['id' => $keyId]) }}"
|
||||||
|
>
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="bg-secondary text-white">
|
<tr class="bg-secondary text-white">
|
||||||
@if (!empty($data))
|
@if (!empty($data))
|
||||||
|
@ -74,6 +76,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -16,6 +16,7 @@ Route::name('opendata.')->prefix('opendata')->group(function () {
|
||||||
Route::name('dataset.')->prefix('dataset')->group(function () {
|
Route::name('dataset.')->prefix('dataset')->group(function () {
|
||||||
Route::resource('/',DatasetController::class);
|
Route::resource('/',DatasetController::class);
|
||||||
Route::get('grid',[DatasetController::class,'grid'])->name('grid');
|
Route::get('grid',[DatasetController::class,'grid'])->name('grid');
|
||||||
|
Route::get('gridDetail',[DatasetController::class,'gridDetail'])->name('gridDetail');
|
||||||
Route::get('update/{id?}',[DatasetController::class,'update'])->name('update');
|
Route::get('update/{id?}',[DatasetController::class,'update'])->name('update');
|
||||||
Route::get('view/{id?}',[DatasetController::class,'view'])->name('view');
|
Route::get('view/{id?}',[DatasetController::class,'view'])->name('view');
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
// autoload.php @generated by Composer
|
|
||||||
|
|
||||||
if (PHP_VERSION_ID < 50600) {
|
|
||||||
if (!headers_sent()) {
|
|
||||||
header('HTTP/1.1 500 Internal Server Error');
|
|
||||||
}
|
|
||||||
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
|
|
||||||
if (!ini_get('display_errors')) {
|
|
||||||
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
|
||||||
fwrite(STDERR, $err);
|
|
||||||
} elseif (!headers_sent()) {
|
|
||||||
echo $err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
trigger_error(
|
|
||||||
$err,
|
|
||||||
E_USER_ERROR
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
require_once __DIR__ . '/composer/autoload_real.php';
|
|
||||||
|
|
||||||
return ComposerAutoloaderInit9c491b8531eec05ba41a11d9276a5749::getLoader();
|
|
|
@ -1,119 +0,0 @@
|
||||||
#!/usr/bin/env php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Proxy PHP file generated by Composer
|
|
||||||
*
|
|
||||||
* This file includes the referenced bin path (../nesbot/carbon/bin/carbon)
|
|
||||||
* using a stream wrapper to prevent the shebang from being output on PHP<8
|
|
||||||
*
|
|
||||||
* @generated
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Composer;
|
|
||||||
|
|
||||||
$GLOBALS['_composer_bin_dir'] = __DIR__;
|
|
||||||
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
|
|
||||||
|
|
||||||
if (PHP_VERSION_ID < 80000) {
|
|
||||||
if (!class_exists('Composer\BinProxyWrapper')) {
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
final class BinProxyWrapper
|
|
||||||
{
|
|
||||||
private $handle;
|
|
||||||
private $position;
|
|
||||||
private $realpath;
|
|
||||||
|
|
||||||
public function stream_open($path, $mode, $options, &$opened_path)
|
|
||||||
{
|
|
||||||
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
|
|
||||||
$opened_path = substr($path, 17);
|
|
||||||
$this->realpath = realpath($opened_path) ?: $opened_path;
|
|
||||||
$opened_path = $this->realpath;
|
|
||||||
$this->handle = fopen($this->realpath, $mode);
|
|
||||||
$this->position = 0;
|
|
||||||
|
|
||||||
return (bool) $this->handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_read($count)
|
|
||||||
{
|
|
||||||
$data = fread($this->handle, $count);
|
|
||||||
|
|
||||||
if ($this->position === 0) {
|
|
||||||
$data = preg_replace('{^#!.*\r?\n}', '', $data);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->position += strlen($data);
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_cast($castAs)
|
|
||||||
{
|
|
||||||
return $this->handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_close()
|
|
||||||
{
|
|
||||||
fclose($this->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_lock($operation)
|
|
||||||
{
|
|
||||||
return $operation ? flock($this->handle, $operation) : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_seek($offset, $whence)
|
|
||||||
{
|
|
||||||
if (0 === fseek($this->handle, $offset, $whence)) {
|
|
||||||
$this->position = ftell($this->handle);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_tell()
|
|
||||||
{
|
|
||||||
return $this->position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_eof()
|
|
||||||
{
|
|
||||||
return feof($this->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_stat()
|
|
||||||
{
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_set_option($option, $arg1, $arg2)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function url_stat($path, $flags)
|
|
||||||
{
|
|
||||||
$path = substr($path, 17);
|
|
||||||
if (file_exists($path)) {
|
|
||||||
return stat($path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|
|
||||||
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
|
|
||||||
) {
|
|
||||||
return include("phpvfscomposer://" . __DIR__ . '/..'.'/nesbot/carbon/bin/carbon');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return include __DIR__ . '/..'.'/nesbot/carbon/bin/carbon';
|
|
|
@ -1,119 +0,0 @@
|
||||||
#!/usr/bin/env php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Proxy PHP file generated by Composer
|
|
||||||
*
|
|
||||||
* This file includes the referenced bin path (../symfony/error-handler/Resources/bin/patch-type-declarations)
|
|
||||||
* using a stream wrapper to prevent the shebang from being output on PHP<8
|
|
||||||
*
|
|
||||||
* @generated
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Composer;
|
|
||||||
|
|
||||||
$GLOBALS['_composer_bin_dir'] = __DIR__;
|
|
||||||
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
|
|
||||||
|
|
||||||
if (PHP_VERSION_ID < 80000) {
|
|
||||||
if (!class_exists('Composer\BinProxyWrapper')) {
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
final class BinProxyWrapper
|
|
||||||
{
|
|
||||||
private $handle;
|
|
||||||
private $position;
|
|
||||||
private $realpath;
|
|
||||||
|
|
||||||
public function stream_open($path, $mode, $options, &$opened_path)
|
|
||||||
{
|
|
||||||
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
|
|
||||||
$opened_path = substr($path, 17);
|
|
||||||
$this->realpath = realpath($opened_path) ?: $opened_path;
|
|
||||||
$opened_path = $this->realpath;
|
|
||||||
$this->handle = fopen($this->realpath, $mode);
|
|
||||||
$this->position = 0;
|
|
||||||
|
|
||||||
return (bool) $this->handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_read($count)
|
|
||||||
{
|
|
||||||
$data = fread($this->handle, $count);
|
|
||||||
|
|
||||||
if ($this->position === 0) {
|
|
||||||
$data = preg_replace('{^#!.*\r?\n}', '', $data);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->position += strlen($data);
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_cast($castAs)
|
|
||||||
{
|
|
||||||
return $this->handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_close()
|
|
||||||
{
|
|
||||||
fclose($this->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_lock($operation)
|
|
||||||
{
|
|
||||||
return $operation ? flock($this->handle, $operation) : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_seek($offset, $whence)
|
|
||||||
{
|
|
||||||
if (0 === fseek($this->handle, $offset, $whence)) {
|
|
||||||
$this->position = ftell($this->handle);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_tell()
|
|
||||||
{
|
|
||||||
return $this->position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_eof()
|
|
||||||
{
|
|
||||||
return feof($this->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_stat()
|
|
||||||
{
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_set_option($option, $arg1, $arg2)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function url_stat($path, $flags)
|
|
||||||
{
|
|
||||||
$path = substr($path, 17);
|
|
||||||
if (file_exists($path)) {
|
|
||||||
return stat($path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|
|
||||||
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
|
|
||||||
) {
|
|
||||||
return include("phpvfscomposer://" . __DIR__ . '/..'.'/symfony/error-handler/Resources/bin/patch-type-declarations');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return include __DIR__ . '/..'.'/symfony/error-handler/Resources/bin/patch-type-declarations';
|
|
|
@ -1,119 +0,0 @@
|
||||||
#!/usr/bin/env php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Proxy PHP file generated by Composer
|
|
||||||
*
|
|
||||||
* This file includes the referenced bin path (../nikic/php-parser/bin/php-parse)
|
|
||||||
* using a stream wrapper to prevent the shebang from being output on PHP<8
|
|
||||||
*
|
|
||||||
* @generated
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Composer;
|
|
||||||
|
|
||||||
$GLOBALS['_composer_bin_dir'] = __DIR__;
|
|
||||||
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
|
|
||||||
|
|
||||||
if (PHP_VERSION_ID < 80000) {
|
|
||||||
if (!class_exists('Composer\BinProxyWrapper')) {
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
final class BinProxyWrapper
|
|
||||||
{
|
|
||||||
private $handle;
|
|
||||||
private $position;
|
|
||||||
private $realpath;
|
|
||||||
|
|
||||||
public function stream_open($path, $mode, $options, &$opened_path)
|
|
||||||
{
|
|
||||||
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
|
|
||||||
$opened_path = substr($path, 17);
|
|
||||||
$this->realpath = realpath($opened_path) ?: $opened_path;
|
|
||||||
$opened_path = $this->realpath;
|
|
||||||
$this->handle = fopen($this->realpath, $mode);
|
|
||||||
$this->position = 0;
|
|
||||||
|
|
||||||
return (bool) $this->handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_read($count)
|
|
||||||
{
|
|
||||||
$data = fread($this->handle, $count);
|
|
||||||
|
|
||||||
if ($this->position === 0) {
|
|
||||||
$data = preg_replace('{^#!.*\r?\n}', '', $data);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->position += strlen($data);
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_cast($castAs)
|
|
||||||
{
|
|
||||||
return $this->handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_close()
|
|
||||||
{
|
|
||||||
fclose($this->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_lock($operation)
|
|
||||||
{
|
|
||||||
return $operation ? flock($this->handle, $operation) : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_seek($offset, $whence)
|
|
||||||
{
|
|
||||||
if (0 === fseek($this->handle, $offset, $whence)) {
|
|
||||||
$this->position = ftell($this->handle);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_tell()
|
|
||||||
{
|
|
||||||
return $this->position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_eof()
|
|
||||||
{
|
|
||||||
return feof($this->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_stat()
|
|
||||||
{
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_set_option($option, $arg1, $arg2)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function url_stat($path, $flags)
|
|
||||||
{
|
|
||||||
$path = substr($path, 17);
|
|
||||||
if (file_exists($path)) {
|
|
||||||
return stat($path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|
|
||||||
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
|
|
||||||
) {
|
|
||||||
return include("phpvfscomposer://" . __DIR__ . '/..'.'/nikic/php-parser/bin/php-parse');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return include __DIR__ . '/..'.'/nikic/php-parser/bin/php-parse';
|
|
|
@ -1,122 +0,0 @@
|
||||||
#!/usr/bin/env php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Proxy PHP file generated by Composer
|
|
||||||
*
|
|
||||||
* This file includes the referenced bin path (../phpunit/phpunit/phpunit)
|
|
||||||
* using a stream wrapper to prevent the shebang from being output on PHP<8
|
|
||||||
*
|
|
||||||
* @generated
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Composer;
|
|
||||||
|
|
||||||
$GLOBALS['_composer_bin_dir'] = __DIR__;
|
|
||||||
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
|
|
||||||
$GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST'] = $GLOBALS['__PHPUNIT_ISOLATION_BLACKLIST'] = array(realpath(__DIR__ . '/..'.'/phpunit/phpunit/phpunit'));
|
|
||||||
|
|
||||||
if (PHP_VERSION_ID < 80000) {
|
|
||||||
if (!class_exists('Composer\BinProxyWrapper')) {
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
final class BinProxyWrapper
|
|
||||||
{
|
|
||||||
private $handle;
|
|
||||||
private $position;
|
|
||||||
private $realpath;
|
|
||||||
|
|
||||||
public function stream_open($path, $mode, $options, &$opened_path)
|
|
||||||
{
|
|
||||||
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
|
|
||||||
$opened_path = substr($path, 17);
|
|
||||||
$this->realpath = realpath($opened_path) ?: $opened_path;
|
|
||||||
$opened_path = 'phpvfscomposer://'.$this->realpath;
|
|
||||||
$this->handle = fopen($this->realpath, $mode);
|
|
||||||
$this->position = 0;
|
|
||||||
|
|
||||||
return (bool) $this->handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_read($count)
|
|
||||||
{
|
|
||||||
$data = fread($this->handle, $count);
|
|
||||||
|
|
||||||
if ($this->position === 0) {
|
|
||||||
$data = preg_replace('{^#!.*\r?\n}', '', $data);
|
|
||||||
}
|
|
||||||
$data = str_replace('__DIR__', var_export(dirname($this->realpath), true), $data);
|
|
||||||
$data = str_replace('__FILE__', var_export($this->realpath, true), $data);
|
|
||||||
|
|
||||||
$this->position += strlen($data);
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_cast($castAs)
|
|
||||||
{
|
|
||||||
return $this->handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_close()
|
|
||||||
{
|
|
||||||
fclose($this->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_lock($operation)
|
|
||||||
{
|
|
||||||
return $operation ? flock($this->handle, $operation) : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_seek($offset, $whence)
|
|
||||||
{
|
|
||||||
if (0 === fseek($this->handle, $offset, $whence)) {
|
|
||||||
$this->position = ftell($this->handle);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_tell()
|
|
||||||
{
|
|
||||||
return $this->position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_eof()
|
|
||||||
{
|
|
||||||
return feof($this->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_stat()
|
|
||||||
{
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_set_option($option, $arg1, $arg2)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function url_stat($path, $flags)
|
|
||||||
{
|
|
||||||
$path = substr($path, 17);
|
|
||||||
if (file_exists($path)) {
|
|
||||||
return stat($path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|
|
||||||
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
|
|
||||||
) {
|
|
||||||
return include("phpvfscomposer://" . __DIR__ . '/..'.'/phpunit/phpunit/phpunit');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return include __DIR__ . '/..'.'/phpunit/phpunit/phpunit';
|
|
|
@ -1,119 +0,0 @@
|
||||||
#!/usr/bin/env php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Proxy PHP file generated by Composer
|
|
||||||
*
|
|
||||||
* This file includes the referenced bin path (../laravel/pint/builds/pint)
|
|
||||||
* using a stream wrapper to prevent the shebang from being output on PHP<8
|
|
||||||
*
|
|
||||||
* @generated
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Composer;
|
|
||||||
|
|
||||||
$GLOBALS['_composer_bin_dir'] = __DIR__;
|
|
||||||
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
|
|
||||||
|
|
||||||
if (PHP_VERSION_ID < 80000) {
|
|
||||||
if (!class_exists('Composer\BinProxyWrapper')) {
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
final class BinProxyWrapper
|
|
||||||
{
|
|
||||||
private $handle;
|
|
||||||
private $position;
|
|
||||||
private $realpath;
|
|
||||||
|
|
||||||
public function stream_open($path, $mode, $options, &$opened_path)
|
|
||||||
{
|
|
||||||
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
|
|
||||||
$opened_path = substr($path, 17);
|
|
||||||
$this->realpath = realpath($opened_path) ?: $opened_path;
|
|
||||||
$opened_path = $this->realpath;
|
|
||||||
$this->handle = fopen($this->realpath, $mode);
|
|
||||||
$this->position = 0;
|
|
||||||
|
|
||||||
return (bool) $this->handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_read($count)
|
|
||||||
{
|
|
||||||
$data = fread($this->handle, $count);
|
|
||||||
|
|
||||||
if ($this->position === 0) {
|
|
||||||
$data = preg_replace('{^#!.*\r?\n}', '', $data);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->position += strlen($data);
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_cast($castAs)
|
|
||||||
{
|
|
||||||
return $this->handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_close()
|
|
||||||
{
|
|
||||||
fclose($this->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_lock($operation)
|
|
||||||
{
|
|
||||||
return $operation ? flock($this->handle, $operation) : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_seek($offset, $whence)
|
|
||||||
{
|
|
||||||
if (0 === fseek($this->handle, $offset, $whence)) {
|
|
||||||
$this->position = ftell($this->handle);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_tell()
|
|
||||||
{
|
|
||||||
return $this->position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_eof()
|
|
||||||
{
|
|
||||||
return feof($this->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_stat()
|
|
||||||
{
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_set_option($option, $arg1, $arg2)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function url_stat($path, $flags)
|
|
||||||
{
|
|
||||||
$path = substr($path, 17);
|
|
||||||
if (file_exists($path)) {
|
|
||||||
return stat($path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|
|
||||||
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
|
|
||||||
) {
|
|
||||||
return include("phpvfscomposer://" . __DIR__ . '/..'.'/laravel/pint/builds/pint');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return include __DIR__ . '/..'.'/laravel/pint/builds/pint';
|
|
|
@ -1,119 +0,0 @@
|
||||||
#!/usr/bin/env php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Proxy PHP file generated by Composer
|
|
||||||
*
|
|
||||||
* This file includes the referenced bin path (../psy/psysh/bin/psysh)
|
|
||||||
* using a stream wrapper to prevent the shebang from being output on PHP<8
|
|
||||||
*
|
|
||||||
* @generated
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Composer;
|
|
||||||
|
|
||||||
$GLOBALS['_composer_bin_dir'] = __DIR__;
|
|
||||||
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
|
|
||||||
|
|
||||||
if (PHP_VERSION_ID < 80000) {
|
|
||||||
if (!class_exists('Composer\BinProxyWrapper')) {
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
final class BinProxyWrapper
|
|
||||||
{
|
|
||||||
private $handle;
|
|
||||||
private $position;
|
|
||||||
private $realpath;
|
|
||||||
|
|
||||||
public function stream_open($path, $mode, $options, &$opened_path)
|
|
||||||
{
|
|
||||||
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
|
|
||||||
$opened_path = substr($path, 17);
|
|
||||||
$this->realpath = realpath($opened_path) ?: $opened_path;
|
|
||||||
$opened_path = $this->realpath;
|
|
||||||
$this->handle = fopen($this->realpath, $mode);
|
|
||||||
$this->position = 0;
|
|
||||||
|
|
||||||
return (bool) $this->handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_read($count)
|
|
||||||
{
|
|
||||||
$data = fread($this->handle, $count);
|
|
||||||
|
|
||||||
if ($this->position === 0) {
|
|
||||||
$data = preg_replace('{^#!.*\r?\n}', '', $data);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->position += strlen($data);
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_cast($castAs)
|
|
||||||
{
|
|
||||||
return $this->handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_close()
|
|
||||||
{
|
|
||||||
fclose($this->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_lock($operation)
|
|
||||||
{
|
|
||||||
return $operation ? flock($this->handle, $operation) : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_seek($offset, $whence)
|
|
||||||
{
|
|
||||||
if (0 === fseek($this->handle, $offset, $whence)) {
|
|
||||||
$this->position = ftell($this->handle);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_tell()
|
|
||||||
{
|
|
||||||
return $this->position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_eof()
|
|
||||||
{
|
|
||||||
return feof($this->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_stat()
|
|
||||||
{
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_set_option($option, $arg1, $arg2)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function url_stat($path, $flags)
|
|
||||||
{
|
|
||||||
$path = substr($path, 17);
|
|
||||||
if (file_exists($path)) {
|
|
||||||
return stat($path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|
|
||||||
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
|
|
||||||
) {
|
|
||||||
return include("phpvfscomposer://" . __DIR__ . '/..'.'/psy/psysh/bin/psysh');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return include __DIR__ . '/..'.'/psy/psysh/bin/psysh';
|
|
|
@ -1,37 +0,0 @@
|
||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
# Support bash to support `source` with fallback on $0 if this does not run with bash
|
|
||||||
# https://stackoverflow.com/a/35006505/6512
|
|
||||||
selfArg="$BASH_SOURCE"
|
|
||||||
if [ -z "$selfArg" ]; then
|
|
||||||
selfArg="$0"
|
|
||||||
fi
|
|
||||||
|
|
||||||
self=$(realpath $selfArg 2> /dev/null)
|
|
||||||
if [ -z "$self" ]; then
|
|
||||||
self="$selfArg"
|
|
||||||
fi
|
|
||||||
|
|
||||||
dir=$(cd "${self%[/\\]*}" > /dev/null; cd '../laravel/sail/bin' && pwd)
|
|
||||||
|
|
||||||
if [ -d /proc/cygdrive ]; then
|
|
||||||
case $(which php) in
|
|
||||||
$(readlink -n /proc/cygdrive)/*)
|
|
||||||
# We are in Cygwin using Windows php, so the path must be translated
|
|
||||||
dir=$(cygpath -m "$dir");
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
export COMPOSER_RUNTIME_BIN_DIR="$(cd "${self%[/\\]*}" > /dev/null; pwd)"
|
|
||||||
|
|
||||||
# If bash is sourcing this file, we have to source the target as well
|
|
||||||
bashSource="$BASH_SOURCE"
|
|
||||||
if [ -n "$bashSource" ]; then
|
|
||||||
if [ "$bashSource" != "$0" ]; then
|
|
||||||
source "${dir}/sail" "$@"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec "${dir}/sail" "$@"
|
|
|
@ -1,119 +0,0 @@
|
||||||
#!/usr/bin/env php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Proxy PHP file generated by Composer
|
|
||||||
*
|
|
||||||
* This file includes the referenced bin path (../symfony/var-dumper/Resources/bin/var-dump-server)
|
|
||||||
* using a stream wrapper to prevent the shebang from being output on PHP<8
|
|
||||||
*
|
|
||||||
* @generated
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Composer;
|
|
||||||
|
|
||||||
$GLOBALS['_composer_bin_dir'] = __DIR__;
|
|
||||||
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
|
|
||||||
|
|
||||||
if (PHP_VERSION_ID < 80000) {
|
|
||||||
if (!class_exists('Composer\BinProxyWrapper')) {
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
final class BinProxyWrapper
|
|
||||||
{
|
|
||||||
private $handle;
|
|
||||||
private $position;
|
|
||||||
private $realpath;
|
|
||||||
|
|
||||||
public function stream_open($path, $mode, $options, &$opened_path)
|
|
||||||
{
|
|
||||||
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
|
|
||||||
$opened_path = substr($path, 17);
|
|
||||||
$this->realpath = realpath($opened_path) ?: $opened_path;
|
|
||||||
$opened_path = $this->realpath;
|
|
||||||
$this->handle = fopen($this->realpath, $mode);
|
|
||||||
$this->position = 0;
|
|
||||||
|
|
||||||
return (bool) $this->handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_read($count)
|
|
||||||
{
|
|
||||||
$data = fread($this->handle, $count);
|
|
||||||
|
|
||||||
if ($this->position === 0) {
|
|
||||||
$data = preg_replace('{^#!.*\r?\n}', '', $data);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->position += strlen($data);
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_cast($castAs)
|
|
||||||
{
|
|
||||||
return $this->handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_close()
|
|
||||||
{
|
|
||||||
fclose($this->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_lock($operation)
|
|
||||||
{
|
|
||||||
return $operation ? flock($this->handle, $operation) : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_seek($offset, $whence)
|
|
||||||
{
|
|
||||||
if (0 === fseek($this->handle, $offset, $whence)) {
|
|
||||||
$this->position = ftell($this->handle);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_tell()
|
|
||||||
{
|
|
||||||
return $this->position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_eof()
|
|
||||||
{
|
|
||||||
return feof($this->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_stat()
|
|
||||||
{
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_set_option($option, $arg1, $arg2)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function url_stat($path, $flags)
|
|
||||||
{
|
|
||||||
$path = substr($path, 17);
|
|
||||||
if (file_exists($path)) {
|
|
||||||
return stat($path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|
|
||||||
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
|
|
||||||
) {
|
|
||||||
return include("phpvfscomposer://" . __DIR__ . '/..'.'/symfony/var-dumper/Resources/bin/var-dump-server');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return include __DIR__ . '/..'.'/symfony/var-dumper/Resources/bin/var-dump-server';
|
|
|
@ -1,119 +0,0 @@
|
||||||
#!/usr/bin/env php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Proxy PHP file generated by Composer
|
|
||||||
*
|
|
||||||
* This file includes the referenced bin path (../symfony/yaml/Resources/bin/yaml-lint)
|
|
||||||
* using a stream wrapper to prevent the shebang from being output on PHP<8
|
|
||||||
*
|
|
||||||
* @generated
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Composer;
|
|
||||||
|
|
||||||
$GLOBALS['_composer_bin_dir'] = __DIR__;
|
|
||||||
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
|
|
||||||
|
|
||||||
if (PHP_VERSION_ID < 80000) {
|
|
||||||
if (!class_exists('Composer\BinProxyWrapper')) {
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
final class BinProxyWrapper
|
|
||||||
{
|
|
||||||
private $handle;
|
|
||||||
private $position;
|
|
||||||
private $realpath;
|
|
||||||
|
|
||||||
public function stream_open($path, $mode, $options, &$opened_path)
|
|
||||||
{
|
|
||||||
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
|
|
||||||
$opened_path = substr($path, 17);
|
|
||||||
$this->realpath = realpath($opened_path) ?: $opened_path;
|
|
||||||
$opened_path = $this->realpath;
|
|
||||||
$this->handle = fopen($this->realpath, $mode);
|
|
||||||
$this->position = 0;
|
|
||||||
|
|
||||||
return (bool) $this->handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_read($count)
|
|
||||||
{
|
|
||||||
$data = fread($this->handle, $count);
|
|
||||||
|
|
||||||
if ($this->position === 0) {
|
|
||||||
$data = preg_replace('{^#!.*\r?\n}', '', $data);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->position += strlen($data);
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_cast($castAs)
|
|
||||||
{
|
|
||||||
return $this->handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_close()
|
|
||||||
{
|
|
||||||
fclose($this->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_lock($operation)
|
|
||||||
{
|
|
||||||
return $operation ? flock($this->handle, $operation) : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_seek($offset, $whence)
|
|
||||||
{
|
|
||||||
if (0 === fseek($this->handle, $offset, $whence)) {
|
|
||||||
$this->position = ftell($this->handle);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_tell()
|
|
||||||
{
|
|
||||||
return $this->position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_eof()
|
|
||||||
{
|
|
||||||
return feof($this->handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_stat()
|
|
||||||
{
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stream_set_option($option, $arg1, $arg2)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function url_stat($path, $flags)
|
|
||||||
{
|
|
||||||
$path = substr($path, 17);
|
|
||||||
if (file_exists($path)) {
|
|
||||||
return stat($path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|
|
||||||
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
|
|
||||||
) {
|
|
||||||
return include("phpvfscomposer://" . __DIR__ . '/..'.'/symfony/yaml/Resources/bin/yaml-lint');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return include __DIR__ . '/..'.'/symfony/yaml/Resources/bin/yaml-lint';
|
|
|
@ -1,479 +0,0 @@
|
||||||
# Changelog
|
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
|
||||||
|
|
||||||
## [0.12.3](https://github.com/brick/math/releases/tag/0.12.3) - 2025-02-28
|
|
||||||
|
|
||||||
✨ **New features**
|
|
||||||
|
|
||||||
- `BigDecimal::getPrecision()` Returns the number of significant digits in a decimal number
|
|
||||||
|
|
||||||
## [0.12.2](https://github.com/brick/math/releases/tag/0.12.2) - 2025-02-26
|
|
||||||
|
|
||||||
⚡️ **Performance improvements**
|
|
||||||
|
|
||||||
- Division in `NativeCalculator` is now faster for small divisors, thanks to [@Izumi-kun](https://github.com/Izumi-kun) in [#87](https://github.com/brick/math/pull/87).
|
|
||||||
|
|
||||||
👌 **Improvements**
|
|
||||||
|
|
||||||
- Add missing `RoundingNecessaryException` to the `@throws` annotation of `BigNumber::of()`
|
|
||||||
|
|
||||||
## [0.12.1](https://github.com/brick/math/releases/tag/0.12.1) - 2023-11-29
|
|
||||||
|
|
||||||
⚡️ **Performance improvements**
|
|
||||||
|
|
||||||
- `BigNumber::of()` is now faster, thanks to [@SebastienDug](https://github.com/SebastienDug) in [#77](https://github.com/brick/math/pull/77).
|
|
||||||
|
|
||||||
## [0.12.0](https://github.com/brick/math/releases/tag/0.12.0) - 2023-11-26
|
|
||||||
|
|
||||||
💥 **Breaking changes**
|
|
||||||
|
|
||||||
- Minimum PHP version is now 8.1
|
|
||||||
- `RoundingMode` is now an `enum`; if you're type-hinting rounding modes, you need to type-hint against `RoundingMode` instead of `int` now
|
|
||||||
- `BigNumber` classes do not implement the `Serializable` interface anymore (they use the [new custom object serialization mechanism](https://wiki.php.net/rfc/custom_object_serialization))
|
|
||||||
- The following breaking changes only affect you if you're creating your own `BigNumber` subclasses:
|
|
||||||
- the return type of `BigNumber::of()` is now `static`
|
|
||||||
- `BigNumber` has a new abstract method `from()`
|
|
||||||
- all `public` and `protected` functions of `BigNumber` are now `final`
|
|
||||||
|
|
||||||
## [0.11.0](https://github.com/brick/math/releases/tag/0.11.0) - 2023-01-16
|
|
||||||
|
|
||||||
💥 **Breaking changes**
|
|
||||||
|
|
||||||
- Minimum PHP version is now 8.0
|
|
||||||
- Methods accepting a union of types are now strongly typed<sup>*</sup>
|
|
||||||
- `MathException` now extends `Exception` instead of `RuntimeException`
|
|
||||||
|
|
||||||
<sup>* You may now run into type errors if you were passing `Stringable` objects to `of()` or any of the methods
|
|
||||||
internally calling `of()`, with `strict_types` enabled. You can fix this by casting `Stringable` objects to `string`
|
|
||||||
first.</sup>
|
|
||||||
|
|
||||||
## [0.10.2](https://github.com/brick/math/releases/tag/0.10.2) - 2022-08-11
|
|
||||||
|
|
||||||
👌 **Improvements**
|
|
||||||
|
|
||||||
- `BigRational::toFloat()` now simplifies the fraction before performing division (#73) thanks to @olsavmic
|
|
||||||
|
|
||||||
## [0.10.1](https://github.com/brick/math/releases/tag/0.10.1) - 2022-08-02
|
|
||||||
|
|
||||||
✨ **New features**
|
|
||||||
|
|
||||||
- `BigInteger::gcdMultiple()` returns the GCD of multiple `BigInteger` numbers
|
|
||||||
|
|
||||||
## [0.10.0](https://github.com/brick/math/releases/tag/0.10.0) - 2022-06-18
|
|
||||||
|
|
||||||
💥 **Breaking changes**
|
|
||||||
|
|
||||||
- Minimum PHP version is now 7.4
|
|
||||||
|
|
||||||
## [0.9.3](https://github.com/brick/math/releases/tag/0.9.3) - 2021-08-15
|
|
||||||
|
|
||||||
🚀 **Compatibility with PHP 8.1**
|
|
||||||
|
|
||||||
- Support for custom object serialization; this removes a warning on PHP 8.1 due to the `Serializable` interface being deprecated (#60) thanks @TRowbotham
|
|
||||||
|
|
||||||
## [0.9.2](https://github.com/brick/math/releases/tag/0.9.2) - 2021-01-20
|
|
||||||
|
|
||||||
🐛 **Bug fix**
|
|
||||||
|
|
||||||
- Incorrect results could be returned when using the BCMath calculator, with a default scale set with `bcscale()`, on PHP >= 7.2 (#55).
|
|
||||||
|
|
||||||
## [0.9.1](https://github.com/brick/math/releases/tag/0.9.1) - 2020-08-19
|
|
||||||
|
|
||||||
✨ **New features**
|
|
||||||
|
|
||||||
- `BigInteger::not()` returns the bitwise `NOT` value
|
|
||||||
|
|
||||||
🐛 **Bug fixes**
|
|
||||||
|
|
||||||
- `BigInteger::toBytes()` could return an incorrect binary representation for some numbers
|
|
||||||
- The bitwise operations `and()`, `or()`, `xor()` on `BigInteger` could return an incorrect result when the GMP extension is not available
|
|
||||||
|
|
||||||
## [0.9.0](https://github.com/brick/math/releases/tag/0.9.0) - 2020-08-18
|
|
||||||
|
|
||||||
👌 **Improvements**
|
|
||||||
|
|
||||||
- `BigNumber::of()` now accepts `.123` and `123.` formats, both of which return a `BigDecimal`
|
|
||||||
|
|
||||||
💥 **Breaking changes**
|
|
||||||
|
|
||||||
- Deprecated method `BigInteger::powerMod()` has been removed - use `modPow()` instead
|
|
||||||
- Deprecated method `BigInteger::parse()` has been removed - use `fromBase()` instead
|
|
||||||
|
|
||||||
## [0.8.17](https://github.com/brick/math/releases/tag/0.8.17) - 2020-08-19
|
|
||||||
|
|
||||||
🐛 **Bug fix**
|
|
||||||
|
|
||||||
- `BigInteger::toBytes()` could return an incorrect binary representation for some numbers
|
|
||||||
- The bitwise operations `and()`, `or()`, `xor()` on `BigInteger` could return an incorrect result when the GMP extension is not available
|
|
||||||
|
|
||||||
## [0.8.16](https://github.com/brick/math/releases/tag/0.8.16) - 2020-08-18
|
|
||||||
|
|
||||||
🚑 **Critical fix**
|
|
||||||
|
|
||||||
- This version reintroduces the deprecated `BigInteger::parse()` method, that has been removed by mistake in version `0.8.9` and should have lasted for the whole `0.8` release cycle.
|
|
||||||
|
|
||||||
✨ **New features**
|
|
||||||
|
|
||||||
- `BigInteger::modInverse()` calculates a modular multiplicative inverse
|
|
||||||
- `BigInteger::fromBytes()` creates a `BigInteger` from a byte string
|
|
||||||
- `BigInteger::toBytes()` converts a `BigInteger` to a byte string
|
|
||||||
- `BigInteger::randomBits()` creates a pseudo-random `BigInteger` of a given bit length
|
|
||||||
- `BigInteger::randomRange()` creates a pseudo-random `BigInteger` between two bounds
|
|
||||||
|
|
||||||
💩 **Deprecations**
|
|
||||||
|
|
||||||
- `BigInteger::powerMod()` is now deprecated in favour of `modPow()`
|
|
||||||
|
|
||||||
## [0.8.15](https://github.com/brick/math/releases/tag/0.8.15) - 2020-04-15
|
|
||||||
|
|
||||||
🐛 **Fixes**
|
|
||||||
|
|
||||||
- added missing `ext-json` requirement, due to `BigNumber` implementing `JsonSerializable`
|
|
||||||
|
|
||||||
⚡️ **Optimizations**
|
|
||||||
|
|
||||||
- additional optimization in `BigInteger::remainder()`
|
|
||||||
|
|
||||||
## [0.8.14](https://github.com/brick/math/releases/tag/0.8.14) - 2020-02-18
|
|
||||||
|
|
||||||
✨ **New features**
|
|
||||||
|
|
||||||
- `BigInteger::getLowestSetBit()` returns the index of the rightmost one bit
|
|
||||||
|
|
||||||
## [0.8.13](https://github.com/brick/math/releases/tag/0.8.13) - 2020-02-16
|
|
||||||
|
|
||||||
✨ **New features**
|
|
||||||
|
|
||||||
- `BigInteger::isEven()` tests whether the number is even
|
|
||||||
- `BigInteger::isOdd()` tests whether the number is odd
|
|
||||||
- `BigInteger::testBit()` tests if a bit is set
|
|
||||||
- `BigInteger::getBitLength()` returns the number of bits in the minimal representation of the number
|
|
||||||
|
|
||||||
## [0.8.12](https://github.com/brick/math/releases/tag/0.8.12) - 2020-02-03
|
|
||||||
|
|
||||||
🛠️ **Maintenance release**
|
|
||||||
|
|
||||||
Classes are now annotated for better static analysis with [psalm](https://psalm.dev/).
|
|
||||||
|
|
||||||
This is a maintenance release: no bug fixes, no new features, no breaking changes.
|
|
||||||
|
|
||||||
## [0.8.11](https://github.com/brick/math/releases/tag/0.8.11) - 2020-01-23
|
|
||||||
|
|
||||||
✨ **New feature**
|
|
||||||
|
|
||||||
`BigInteger::powerMod()` performs a power-with-modulo operation. Useful for crypto.
|
|
||||||
|
|
||||||
## [0.8.10](https://github.com/brick/math/releases/tag/0.8.10) - 2020-01-21
|
|
||||||
|
|
||||||
✨ **New feature**
|
|
||||||
|
|
||||||
`BigInteger::mod()` returns the **modulo** of two numbers. The *modulo* differs from the *remainder* when the signs of the operands are different.
|
|
||||||
|
|
||||||
## [0.8.9](https://github.com/brick/math/releases/tag/0.8.9) - 2020-01-08
|
|
||||||
|
|
||||||
⚡️ **Performance improvements**
|
|
||||||
|
|
||||||
A few additional optimizations in `BigInteger` and `BigDecimal` when one of the operands can be returned as is. Thanks to @tomtomsen in #24.
|
|
||||||
|
|
||||||
## [0.8.8](https://github.com/brick/math/releases/tag/0.8.8) - 2019-04-25
|
|
||||||
|
|
||||||
🐛 **Bug fixes**
|
|
||||||
|
|
||||||
- `BigInteger::toBase()` could return an empty string for zero values (BCMath & Native calculators only, GMP calculator unaffected)
|
|
||||||
|
|
||||||
✨ **New features**
|
|
||||||
|
|
||||||
- `BigInteger::toArbitraryBase()` converts a number to an arbitrary base, using a custom alphabet
|
|
||||||
- `BigInteger::fromArbitraryBase()` converts a string in an arbitrary base, using a custom alphabet, back to a number
|
|
||||||
|
|
||||||
These methods can be used as the foundation to convert strings between different bases/alphabets, using BigInteger as an intermediate representation.
|
|
||||||
|
|
||||||
💩 **Deprecations**
|
|
||||||
|
|
||||||
- `BigInteger::parse()` is now deprecated in favour of `fromBase()`
|
|
||||||
|
|
||||||
`BigInteger::fromBase()` works the same way as `parse()`, with 2 minor differences:
|
|
||||||
|
|
||||||
- the `$base` parameter is required, it does not default to `10`
|
|
||||||
- it throws a `NumberFormatException` instead of an `InvalidArgumentException` when the number is malformed
|
|
||||||
|
|
||||||
## [0.8.7](https://github.com/brick/math/releases/tag/0.8.7) - 2019-04-20
|
|
||||||
|
|
||||||
**Improvements**
|
|
||||||
|
|
||||||
- Safer conversion from `float` when using custom locales
|
|
||||||
- **Much faster** `NativeCalculator` implementation 🚀
|
|
||||||
|
|
||||||
You can expect **at least a 3x performance improvement** for common arithmetic operations when using the library on systems without GMP or BCMath; it gets exponentially faster on multiplications with a high number of digits. This is due to calculations now being performed on whole blocks of digits (the block size depending on the platform, 32-bit or 64-bit) instead of digit-by-digit as before.
|
|
||||||
|
|
||||||
## [0.8.6](https://github.com/brick/math/releases/tag/0.8.6) - 2019-04-11
|
|
||||||
|
|
||||||
**New method**
|
|
||||||
|
|
||||||
`BigNumber::sum()` returns the sum of one or more numbers.
|
|
||||||
|
|
||||||
## [0.8.5](https://github.com/brick/math/releases/tag/0.8.5) - 2019-02-12
|
|
||||||
|
|
||||||
**Bug fix**: `of()` factory methods could fail when passing a `float` in environments using a `LC_NUMERIC` locale with a decimal separator other than `'.'` (#20).
|
|
||||||
|
|
||||||
Thanks @manowark 👍
|
|
||||||
|
|
||||||
## [0.8.4](https://github.com/brick/math/releases/tag/0.8.4) - 2018-12-07
|
|
||||||
|
|
||||||
**New method**
|
|
||||||
|
|
||||||
`BigDecimal::sqrt()` calculates the square root of a decimal number, to a given scale.
|
|
||||||
|
|
||||||
## [0.8.3](https://github.com/brick/math/releases/tag/0.8.3) - 2018-12-06
|
|
||||||
|
|
||||||
**New method**
|
|
||||||
|
|
||||||
`BigInteger::sqrt()` calculates the square root of a number (thanks @peter279k).
|
|
||||||
|
|
||||||
**New exception**
|
|
||||||
|
|
||||||
`NegativeNumberException` is thrown when calling `sqrt()` on a negative number.
|
|
||||||
|
|
||||||
## [0.8.2](https://github.com/brick/math/releases/tag/0.8.2) - 2018-11-08
|
|
||||||
|
|
||||||
**Performance update**
|
|
||||||
|
|
||||||
- Further improvement of `toInt()` performance
|
|
||||||
- `NativeCalculator` can now perform some multiplications more efficiently
|
|
||||||
|
|
||||||
## [0.8.1](https://github.com/brick/math/releases/tag/0.8.1) - 2018-11-07
|
|
||||||
|
|
||||||
Performance optimization of `toInt()` methods.
|
|
||||||
|
|
||||||
## [0.8.0](https://github.com/brick/math/releases/tag/0.8.0) - 2018-10-13
|
|
||||||
|
|
||||||
**Breaking changes**
|
|
||||||
|
|
||||||
The following deprecated methods have been removed. Use the new method name instead:
|
|
||||||
|
|
||||||
| Method removed | Replacement method |
|
|
||||||
| --- | --- |
|
|
||||||
| `BigDecimal::getIntegral()` | `BigDecimal::getIntegralPart()` |
|
|
||||||
| `BigDecimal::getFraction()` | `BigDecimal::getFractionalPart()` |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**New features**
|
|
||||||
|
|
||||||
`BigInteger` has been augmented with 5 new methods for bitwise operations:
|
|
||||||
|
|
||||||
| New method | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `and()` | performs a bitwise `AND` operation on two numbers |
|
|
||||||
| `or()` | performs a bitwise `OR` operation on two numbers |
|
|
||||||
| `xor()` | performs a bitwise `XOR` operation on two numbers |
|
|
||||||
| `shiftedLeft()` | returns the number shifted left by a number of bits |
|
|
||||||
| `shiftedRight()` | returns the number shifted right by a number of bits |
|
|
||||||
|
|
||||||
Thanks to @DASPRiD 👍
|
|
||||||
|
|
||||||
## [0.7.3](https://github.com/brick/math/releases/tag/0.7.3) - 2018-08-20
|
|
||||||
|
|
||||||
**New method:** `BigDecimal::hasNonZeroFractionalPart()`
|
|
||||||
|
|
||||||
**Renamed/deprecated methods:**
|
|
||||||
|
|
||||||
- `BigDecimal::getIntegral()` has been renamed to `getIntegralPart()` and is now deprecated
|
|
||||||
- `BigDecimal::getFraction()` has been renamed to `getFractionalPart()` and is now deprecated
|
|
||||||
|
|
||||||
## [0.7.2](https://github.com/brick/math/releases/tag/0.7.2) - 2018-07-21
|
|
||||||
|
|
||||||
**Performance update**
|
|
||||||
|
|
||||||
`BigInteger::parse()` and `toBase()` now use GMP's built-in base conversion features when available.
|
|
||||||
|
|
||||||
## [0.7.1](https://github.com/brick/math/releases/tag/0.7.1) - 2018-03-01
|
|
||||||
|
|
||||||
This is a maintenance release, no code has been changed.
|
|
||||||
|
|
||||||
- When installed with `--no-dev`, the autoloader does not autoload tests anymore
|
|
||||||
- Tests and other files unnecessary for production are excluded from the dist package
|
|
||||||
|
|
||||||
This will help make installations more compact.
|
|
||||||
|
|
||||||
## [0.7.0](https://github.com/brick/math/releases/tag/0.7.0) - 2017-10-02
|
|
||||||
|
|
||||||
Methods renamed:
|
|
||||||
|
|
||||||
- `BigNumber:sign()` has been renamed to `getSign()`
|
|
||||||
- `BigDecimal::unscaledValue()` has been renamed to `getUnscaledValue()`
|
|
||||||
- `BigDecimal::scale()` has been renamed to `getScale()`
|
|
||||||
- `BigDecimal::integral()` has been renamed to `getIntegral()`
|
|
||||||
- `BigDecimal::fraction()` has been renamed to `getFraction()`
|
|
||||||
- `BigRational::numerator()` has been renamed to `getNumerator()`
|
|
||||||
- `BigRational::denominator()` has been renamed to `getDenominator()`
|
|
||||||
|
|
||||||
Classes renamed:
|
|
||||||
|
|
||||||
- `ArithmeticException` has been renamed to `MathException`
|
|
||||||
|
|
||||||
## [0.6.2](https://github.com/brick/math/releases/tag/0.6.2) - 2017-10-02
|
|
||||||
|
|
||||||
The base class for all exceptions is now `MathException`.
|
|
||||||
`ArithmeticException` has been deprecated, and will be removed in 0.7.0.
|
|
||||||
|
|
||||||
## [0.6.1](https://github.com/brick/math/releases/tag/0.6.1) - 2017-10-02
|
|
||||||
|
|
||||||
A number of methods have been renamed:
|
|
||||||
|
|
||||||
- `BigNumber:sign()` is deprecated; use `getSign()` instead
|
|
||||||
- `BigDecimal::unscaledValue()` is deprecated; use `getUnscaledValue()` instead
|
|
||||||
- `BigDecimal::scale()` is deprecated; use `getScale()` instead
|
|
||||||
- `BigDecimal::integral()` is deprecated; use `getIntegral()` instead
|
|
||||||
- `BigDecimal::fraction()` is deprecated; use `getFraction()` instead
|
|
||||||
- `BigRational::numerator()` is deprecated; use `getNumerator()` instead
|
|
||||||
- `BigRational::denominator()` is deprecated; use `getDenominator()` instead
|
|
||||||
|
|
||||||
The old methods will be removed in version 0.7.0.
|
|
||||||
|
|
||||||
## [0.6.0](https://github.com/brick/math/releases/tag/0.6.0) - 2017-08-25
|
|
||||||
|
|
||||||
- Minimum PHP version is now [7.1](https://gophp71.org/); for PHP 5.6 and PHP 7.0 support, use version `0.5`
|
|
||||||
- Deprecated method `BigDecimal::withScale()` has been removed; use `toScale()` instead
|
|
||||||
- Method `BigNumber::toInteger()` has been renamed to `toInt()`
|
|
||||||
|
|
||||||
## [0.5.4](https://github.com/brick/math/releases/tag/0.5.4) - 2016-10-17
|
|
||||||
|
|
||||||
`BigNumber` classes now implement [JsonSerializable](http://php.net/manual/en/class.jsonserializable.php).
|
|
||||||
The JSON output is always a string.
|
|
||||||
|
|
||||||
## [0.5.3](https://github.com/brick/math/releases/tag/0.5.3) - 2016-03-31
|
|
||||||
|
|
||||||
This is a bugfix release. Dividing by a negative power of 1 with the same scale as the dividend could trigger an incorrect optimization which resulted in a wrong result. See #6.
|
|
||||||
|
|
||||||
## [0.5.2](https://github.com/brick/math/releases/tag/0.5.2) - 2015-08-06
|
|
||||||
|
|
||||||
The `$scale` parameter of `BigDecimal::dividedBy()` is now optional again.
|
|
||||||
|
|
||||||
## [0.5.1](https://github.com/brick/math/releases/tag/0.5.1) - 2015-07-05
|
|
||||||
|
|
||||||
**New method: `BigNumber::toScale()`**
|
|
||||||
|
|
||||||
This allows to convert any `BigNumber` to a `BigDecimal` with a given scale, using rounding if necessary.
|
|
||||||
|
|
||||||
## [0.5.0](https://github.com/brick/math/releases/tag/0.5.0) - 2015-07-04
|
|
||||||
|
|
||||||
**New features**
|
|
||||||
- Common `BigNumber` interface for all classes, with the following methods:
|
|
||||||
- `sign()` and derived methods (`isZero()`, `isPositive()`, ...)
|
|
||||||
- `compareTo()` and derived methods (`isEqualTo()`, `isGreaterThan()`, ...) that work across different `BigNumber` types
|
|
||||||
- `toBigInteger()`, `toBigDecimal()`, `toBigRational`() conversion methods
|
|
||||||
- `toInteger()` and `toFloat()` conversion methods to native types
|
|
||||||
- Unified `of()` behaviour: every class now accepts any type of number, provided that it can be safely converted to the current type
|
|
||||||
- New method: `BigDecimal::exactlyDividedBy()`; this method automatically computes the scale of the result, provided that the division yields a finite number of digits
|
|
||||||
- New methods: `BigRational::quotient()` and `remainder()`
|
|
||||||
- Fine-grained exceptions: `DivisionByZeroException`, `RoundingNecessaryException`, `NumberFormatException`
|
|
||||||
- Factory methods `zero()`, `one()` and `ten()` available in all classes
|
|
||||||
- Rounding mode reintroduced in `BigInteger::dividedBy()`
|
|
||||||
|
|
||||||
This release also comes with many performance improvements.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Breaking changes**
|
|
||||||
- `BigInteger`:
|
|
||||||
- `getSign()` is renamed to `sign()`
|
|
||||||
- `toString()` is renamed to `toBase()`
|
|
||||||
- `BigInteger::dividedBy()` now throws an exception by default if the remainder is not zero; use `quotient()` to get the previous behaviour
|
|
||||||
- `BigDecimal`:
|
|
||||||
- `getSign()` is renamed to `sign()`
|
|
||||||
- `getUnscaledValue()` is renamed to `unscaledValue()`
|
|
||||||
- `getScale()` is renamed to `scale()`
|
|
||||||
- `getIntegral()` is renamed to `integral()`
|
|
||||||
- `getFraction()` is renamed to `fraction()`
|
|
||||||
- `divideAndRemainder()` is renamed to `quotientAndRemainder()`
|
|
||||||
- `dividedBy()` now takes a **mandatory** `$scale` parameter **before** the rounding mode
|
|
||||||
- `toBigInteger()` does not accept a `$roundingMode` parameter anymore
|
|
||||||
- `toBigRational()` does not simplify the fraction anymore; explicitly add `->simplified()` to get the previous behaviour
|
|
||||||
- `BigRational`:
|
|
||||||
- `getSign()` is renamed to `sign()`
|
|
||||||
- `getNumerator()` is renamed to `numerator()`
|
|
||||||
- `getDenominator()` is renamed to `denominator()`
|
|
||||||
- `of()` is renamed to `nd()`, while `parse()` is renamed to `of()`
|
|
||||||
- Miscellaneous:
|
|
||||||
- `ArithmeticException` is moved to an `Exception\` sub-namespace
|
|
||||||
- `of()` factory methods now throw `NumberFormatException` instead of `InvalidArgumentException`
|
|
||||||
|
|
||||||
## [0.4.3](https://github.com/brick/math/releases/tag/0.4.3) - 2016-03-31
|
|
||||||
|
|
||||||
Backport of two bug fixes from the 0.5 branch:
|
|
||||||
- `BigInteger::parse()` did not always throw `InvalidArgumentException` as expected
|
|
||||||
- Dividing by a negative power of 1 with the same scale as the dividend could trigger an incorrect optimization which resulted in a wrong result. See #6.
|
|
||||||
|
|
||||||
## [0.4.2](https://github.com/brick/math/releases/tag/0.4.2) - 2015-06-16
|
|
||||||
|
|
||||||
New method: `BigDecimal::stripTrailingZeros()`
|
|
||||||
|
|
||||||
## [0.4.1](https://github.com/brick/math/releases/tag/0.4.1) - 2015-06-12
|
|
||||||
|
|
||||||
Introducing a `BigRational` class, to perform calculations on fractions of any size.
|
|
||||||
|
|
||||||
## [0.4.0](https://github.com/brick/math/releases/tag/0.4.0) - 2015-06-12
|
|
||||||
|
|
||||||
Rounding modes have been removed from `BigInteger`, and are now a concept specific to `BigDecimal`.
|
|
||||||
|
|
||||||
`BigInteger::dividedBy()` now always returns the quotient of the division.
|
|
||||||
|
|
||||||
## [0.3.5](https://github.com/brick/math/releases/tag/0.3.5) - 2016-03-31
|
|
||||||
|
|
||||||
Backport of two bug fixes from the 0.5 branch:
|
|
||||||
|
|
||||||
- `BigInteger::parse()` did not always throw `InvalidArgumentException` as expected
|
|
||||||
- Dividing by a negative power of 1 with the same scale as the dividend could trigger an incorrect optimization which resulted in a wrong result. See #6.
|
|
||||||
|
|
||||||
## [0.3.4](https://github.com/brick/math/releases/tag/0.3.4) - 2015-06-11
|
|
||||||
|
|
||||||
New methods:
|
|
||||||
- `BigInteger::remainder()` returns the remainder of a division only
|
|
||||||
- `BigInteger::gcd()` returns the greatest common divisor of two numbers
|
|
||||||
|
|
||||||
## [0.3.3](https://github.com/brick/math/releases/tag/0.3.3) - 2015-06-07
|
|
||||||
|
|
||||||
Fix `toString()` not handling negative numbers.
|
|
||||||
|
|
||||||
## [0.3.2](https://github.com/brick/math/releases/tag/0.3.2) - 2015-06-07
|
|
||||||
|
|
||||||
`BigInteger` and `BigDecimal` now have a `getSign()` method that returns:
|
|
||||||
- `-1` if the number is negative
|
|
||||||
- `0` if the number is zero
|
|
||||||
- `1` if the number is positive
|
|
||||||
|
|
||||||
## [0.3.1](https://github.com/brick/math/releases/tag/0.3.1) - 2015-06-05
|
|
||||||
|
|
||||||
Minor performance improvements
|
|
||||||
|
|
||||||
## [0.3.0](https://github.com/brick/math/releases/tag/0.3.0) - 2015-06-04
|
|
||||||
|
|
||||||
The `$roundingMode` and `$scale` parameters have been swapped in `BigDecimal::dividedBy()`.
|
|
||||||
|
|
||||||
## [0.2.2](https://github.com/brick/math/releases/tag/0.2.2) - 2015-06-04
|
|
||||||
|
|
||||||
Stronger immutability guarantee for `BigInteger` and `BigDecimal`.
|
|
||||||
|
|
||||||
So far, it would have been possible to break immutability of these classes by calling the `unserialize()` internal function. This release fixes that.
|
|
||||||
|
|
||||||
## [0.2.1](https://github.com/brick/math/releases/tag/0.2.1) - 2015-06-02
|
|
||||||
|
|
||||||
Added `BigDecimal::divideAndRemainder()`
|
|
||||||
|
|
||||||
## [0.2.0](https://github.com/brick/math/releases/tag/0.2.0) - 2015-05-22
|
|
||||||
|
|
||||||
- `min()` and `max()` do not accept an `array` anymore, but a variable number of parameters
|
|
||||||
- **minimum PHP version is now 5.6**
|
|
||||||
- continuous integration with PHP 7
|
|
||||||
|
|
||||||
## [0.1.1](https://github.com/brick/math/releases/tag/0.1.1) - 2014-09-01
|
|
||||||
|
|
||||||
- Added `BigInteger::power()`
|
|
||||||
- Added HHVM support
|
|
||||||
|
|
||||||
## [0.1.0](https://github.com/brick/math/releases/tag/0.1.0) - 2014-08-31
|
|
||||||
|
|
||||||
First beta release.
|
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2013-present Benjamin Morel
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
||||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
||||||
subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
||||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
||||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
@ -1,39 +0,0 @@
|
||||||
{
|
|
||||||
"name": "brick/math",
|
|
||||||
"description": "Arbitrary-precision arithmetic library",
|
|
||||||
"type": "library",
|
|
||||||
"keywords": [
|
|
||||||
"Brick",
|
|
||||||
"Math",
|
|
||||||
"Mathematics",
|
|
||||||
"Arbitrary-precision",
|
|
||||||
"Arithmetic",
|
|
||||||
"BigInteger",
|
|
||||||
"BigDecimal",
|
|
||||||
"BigRational",
|
|
||||||
"BigNumber",
|
|
||||||
"Bignum",
|
|
||||||
"Decimal",
|
|
||||||
"Rational",
|
|
||||||
"Integer"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"require": {
|
|
||||||
"php": "^8.1"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"phpunit/phpunit": "^10.1",
|
|
||||||
"php-coveralls/php-coveralls": "^2.2",
|
|
||||||
"vimeo/psalm": "6.8.8"
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Brick\\Math\\": "src/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload-dev": {
|
|
||||||
"psr-4": {
|
|
||||||
"Brick\\Math\\Tests\\": "tests/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<files psalm-version="6.8.8@1361cd33008feb3ae2b4a93f1860e14e538ec8c2">
|
|
||||||
<file src="src/BigInteger.php">
|
|
||||||
<FalsableReturnStatement>
|
|
||||||
<code><![CDATA[\hex2bin($hex)]]></code>
|
|
||||||
</FalsableReturnStatement>
|
|
||||||
<InvalidFalsableReturnType>
|
|
||||||
<code><![CDATA[string]]></code>
|
|
||||||
</InvalidFalsableReturnType>
|
|
||||||
</file>
|
|
||||||
<file src="src/Exception/DivisionByZeroException.php">
|
|
||||||
<ClassMustBeFinal>
|
|
||||||
<code><![CDATA[DivisionByZeroException]]></code>
|
|
||||||
</ClassMustBeFinal>
|
|
||||||
</file>
|
|
||||||
<file src="src/Exception/IntegerOverflowException.php">
|
|
||||||
<ClassMustBeFinal>
|
|
||||||
<code><![CDATA[IntegerOverflowException]]></code>
|
|
||||||
</ClassMustBeFinal>
|
|
||||||
</file>
|
|
||||||
<file src="src/Exception/NegativeNumberException.php">
|
|
||||||
<ClassMustBeFinal>
|
|
||||||
<code><![CDATA[NegativeNumberException]]></code>
|
|
||||||
</ClassMustBeFinal>
|
|
||||||
</file>
|
|
||||||
<file src="src/Exception/NumberFormatException.php">
|
|
||||||
<ClassMustBeFinal>
|
|
||||||
<code><![CDATA[NumberFormatException]]></code>
|
|
||||||
</ClassMustBeFinal>
|
|
||||||
</file>
|
|
||||||
<file src="src/Exception/RoundingNecessaryException.php">
|
|
||||||
<ClassMustBeFinal>
|
|
||||||
<code><![CDATA[RoundingNecessaryException]]></code>
|
|
||||||
</ClassMustBeFinal>
|
|
||||||
</file>
|
|
||||||
<file src="src/Internal/Calculator/BcMathCalculator.php">
|
|
||||||
<ClassMustBeFinal>
|
|
||||||
<code><![CDATA[BcMathCalculator]]></code>
|
|
||||||
</ClassMustBeFinal>
|
|
||||||
</file>
|
|
||||||
<file src="src/Internal/Calculator/GmpCalculator.php">
|
|
||||||
<ClassMustBeFinal>
|
|
||||||
<code><![CDATA[GmpCalculator]]></code>
|
|
||||||
</ClassMustBeFinal>
|
|
||||||
</file>
|
|
||||||
<file src="src/Internal/Calculator/NativeCalculator.php">
|
|
||||||
<ClassMustBeFinal>
|
|
||||||
<code><![CDATA[NativeCalculator]]></code>
|
|
||||||
</ClassMustBeFinal>
|
|
||||||
<InvalidOperand>
|
|
||||||
<code><![CDATA[$a * $b]]></code>
|
|
||||||
<code><![CDATA[$a * 1]]></code>
|
|
||||||
<code><![CDATA[$a + $b]]></code>
|
|
||||||
<code><![CDATA[$b * 1]]></code>
|
|
||||||
<code><![CDATA[$b * 1]]></code>
|
|
||||||
<code><![CDATA[$blockA * $blockB + $carry]]></code>
|
|
||||||
<code><![CDATA[$blockA + $blockB]]></code>
|
|
||||||
<code><![CDATA[$blockA + $blockB + $carry]]></code>
|
|
||||||
<code><![CDATA[$blockA - $blockB]]></code>
|
|
||||||
<code><![CDATA[$blockA - $blockB - $carry]]></code>
|
|
||||||
<code><![CDATA[$carry]]></code>
|
|
||||||
<code><![CDATA[$mul % $complement]]></code>
|
|
||||||
<code><![CDATA[$mul - $value]]></code>
|
|
||||||
<code><![CDATA[$nb - 1]]></code>
|
|
||||||
<code><![CDATA[$sum += $complement]]></code>
|
|
||||||
<code><![CDATA[($mul - $value) / $complement]]></code>
|
|
||||||
<code><![CDATA[($nb - 1) * 10]]></code>
|
|
||||||
</InvalidOperand>
|
|
||||||
</file>
|
|
||||||
</files>
|
|
|
@ -1,792 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Brick\Math;
|
|
||||||
|
|
||||||
use Brick\Math\Exception\DivisionByZeroException;
|
|
||||||
use Brick\Math\Exception\MathException;
|
|
||||||
use Brick\Math\Exception\NegativeNumberException;
|
|
||||||
use Brick\Math\Internal\Calculator;
|
|
||||||
use Override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Immutable, arbitrary-precision signed decimal numbers.
|
|
||||||
*
|
|
||||||
* @psalm-immutable
|
|
||||||
*/
|
|
||||||
final class BigDecimal extends BigNumber
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The unscaled value of this decimal number.
|
|
||||||
*
|
|
||||||
* This is a string of digits with an optional leading minus sign.
|
|
||||||
* No leading zero must be present.
|
|
||||||
* No leading minus sign must be present if the value is 0.
|
|
||||||
*/
|
|
||||||
private readonly string $value;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The scale (number of digits after the decimal point) of this decimal number.
|
|
||||||
*
|
|
||||||
* This must be zero or more.
|
|
||||||
*/
|
|
||||||
private readonly int $scale;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Protected constructor. Use a factory method to obtain an instance.
|
|
||||||
*
|
|
||||||
* @param string $value The unscaled value, validated.
|
|
||||||
* @param int $scale The scale, validated.
|
|
||||||
*/
|
|
||||||
protected function __construct(string $value, int $scale = 0)
|
|
||||||
{
|
|
||||||
$this->value = $value;
|
|
||||||
$this->scale = $scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
#[Override]
|
|
||||||
protected static function from(BigNumber $number): static
|
|
||||||
{
|
|
||||||
return $number->toBigDecimal();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a BigDecimal from an unscaled value and a scale.
|
|
||||||
*
|
|
||||||
* Example: `(12345, 3)` will result in the BigDecimal `12.345`.
|
|
||||||
*
|
|
||||||
* @param BigNumber|int|float|string $value The unscaled value. Must be convertible to a BigInteger.
|
|
||||||
* @param int $scale The scale of the number, positive or zero.
|
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException If the scale is negative.
|
|
||||||
*
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
public static function ofUnscaledValue(BigNumber|int|float|string $value, int $scale = 0) : BigDecimal
|
|
||||||
{
|
|
||||||
if ($scale < 0) {
|
|
||||||
throw new \InvalidArgumentException('The scale cannot be negative.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BigDecimal((string) BigInteger::of($value), $scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a BigDecimal representing zero, with a scale of zero.
|
|
||||||
*
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
public static function zero() : BigDecimal
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @psalm-suppress ImpureStaticVariable
|
|
||||||
* @var BigDecimal|null $zero
|
|
||||||
*/
|
|
||||||
static $zero;
|
|
||||||
|
|
||||||
if ($zero === null) {
|
|
||||||
$zero = new BigDecimal('0');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $zero;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a BigDecimal representing one, with a scale of zero.
|
|
||||||
*
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
public static function one() : BigDecimal
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @psalm-suppress ImpureStaticVariable
|
|
||||||
* @var BigDecimal|null $one
|
|
||||||
*/
|
|
||||||
static $one;
|
|
||||||
|
|
||||||
if ($one === null) {
|
|
||||||
$one = new BigDecimal('1');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $one;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a BigDecimal representing ten, with a scale of zero.
|
|
||||||
*
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
public static function ten() : BigDecimal
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @psalm-suppress ImpureStaticVariable
|
|
||||||
* @var BigDecimal|null $ten
|
|
||||||
*/
|
|
||||||
static $ten;
|
|
||||||
|
|
||||||
if ($ten === null) {
|
|
||||||
$ten = new BigDecimal('10');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $ten;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the sum of this number and the given one.
|
|
||||||
*
|
|
||||||
* The result has a scale of `max($this->scale, $that->scale)`.
|
|
||||||
*
|
|
||||||
* @param BigNumber|int|float|string $that The number to add. Must be convertible to a BigDecimal.
|
|
||||||
*
|
|
||||||
* @throws MathException If the number is not valid, or is not convertible to a BigDecimal.
|
|
||||||
*/
|
|
||||||
public function plus(BigNumber|int|float|string $that) : BigDecimal
|
|
||||||
{
|
|
||||||
$that = BigDecimal::of($that);
|
|
||||||
|
|
||||||
if ($that->value === '0' && $that->scale <= $this->scale) {
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->value === '0' && $this->scale <= $that->scale) {
|
|
||||||
return $that;
|
|
||||||
}
|
|
||||||
|
|
||||||
[$a, $b] = $this->scaleValues($this, $that);
|
|
||||||
|
|
||||||
$value = Calculator::get()->add($a, $b);
|
|
||||||
$scale = $this->scale > $that->scale ? $this->scale : $that->scale;
|
|
||||||
|
|
||||||
return new BigDecimal($value, $scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the difference of this number and the given one.
|
|
||||||
*
|
|
||||||
* The result has a scale of `max($this->scale, $that->scale)`.
|
|
||||||
*
|
|
||||||
* @param BigNumber|int|float|string $that The number to subtract. Must be convertible to a BigDecimal.
|
|
||||||
*
|
|
||||||
* @throws MathException If the number is not valid, or is not convertible to a BigDecimal.
|
|
||||||
*/
|
|
||||||
public function minus(BigNumber|int|float|string $that) : BigDecimal
|
|
||||||
{
|
|
||||||
$that = BigDecimal::of($that);
|
|
||||||
|
|
||||||
if ($that->value === '0' && $that->scale <= $this->scale) {
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
[$a, $b] = $this->scaleValues($this, $that);
|
|
||||||
|
|
||||||
$value = Calculator::get()->sub($a, $b);
|
|
||||||
$scale = $this->scale > $that->scale ? $this->scale : $that->scale;
|
|
||||||
|
|
||||||
return new BigDecimal($value, $scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the product of this number and the given one.
|
|
||||||
*
|
|
||||||
* The result has a scale of `$this->scale + $that->scale`.
|
|
||||||
*
|
|
||||||
* @param BigNumber|int|float|string $that The multiplier. Must be convertible to a BigDecimal.
|
|
||||||
*
|
|
||||||
* @throws MathException If the multiplier is not a valid number, or is not convertible to a BigDecimal.
|
|
||||||
*/
|
|
||||||
public function multipliedBy(BigNumber|int|float|string $that) : BigDecimal
|
|
||||||
{
|
|
||||||
$that = BigDecimal::of($that);
|
|
||||||
|
|
||||||
if ($that->value === '1' && $that->scale === 0) {
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->value === '1' && $this->scale === 0) {
|
|
||||||
return $that;
|
|
||||||
}
|
|
||||||
|
|
||||||
$value = Calculator::get()->mul($this->value, $that->value);
|
|
||||||
$scale = $this->scale + $that->scale;
|
|
||||||
|
|
||||||
return new BigDecimal($value, $scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the result of the division of this number by the given one, at the given scale.
|
|
||||||
*
|
|
||||||
* @param BigNumber|int|float|string $that The divisor.
|
|
||||||
* @param int|null $scale The desired scale, or null to use the scale of this number.
|
|
||||||
* @param RoundingMode $roundingMode An optional rounding mode, defaults to UNNECESSARY.
|
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException If the scale or rounding mode is invalid.
|
|
||||||
* @throws MathException If the number is invalid, is zero, or rounding was necessary.
|
|
||||||
*/
|
|
||||||
public function dividedBy(BigNumber|int|float|string $that, ?int $scale = null, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
|
|
||||||
{
|
|
||||||
$that = BigDecimal::of($that);
|
|
||||||
|
|
||||||
if ($that->isZero()) {
|
|
||||||
throw DivisionByZeroException::divisionByZero();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($scale === null) {
|
|
||||||
$scale = $this->scale;
|
|
||||||
} elseif ($scale < 0) {
|
|
||||||
throw new \InvalidArgumentException('Scale cannot be negative.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($that->value === '1' && $that->scale === 0 && $scale === $this->scale) {
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
$p = $this->valueWithMinScale($that->scale + $scale);
|
|
||||||
$q = $that->valueWithMinScale($this->scale - $scale);
|
|
||||||
|
|
||||||
$result = Calculator::get()->divRound($p, $q, $roundingMode);
|
|
||||||
|
|
||||||
return new BigDecimal($result, $scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the exact result of the division of this number by the given one.
|
|
||||||
*
|
|
||||||
* The scale of the result is automatically calculated to fit all the fraction digits.
|
|
||||||
*
|
|
||||||
* @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal.
|
|
||||||
*
|
|
||||||
* @throws MathException If the divisor is not a valid number, is not convertible to a BigDecimal, is zero,
|
|
||||||
* or the result yields an infinite number of digits.
|
|
||||||
*/
|
|
||||||
public function exactlyDividedBy(BigNumber|int|float|string $that) : BigDecimal
|
|
||||||
{
|
|
||||||
$that = BigDecimal::of($that);
|
|
||||||
|
|
||||||
if ($that->value === '0') {
|
|
||||||
throw DivisionByZeroException::divisionByZero();
|
|
||||||
}
|
|
||||||
|
|
||||||
[, $b] = $this->scaleValues($this, $that);
|
|
||||||
|
|
||||||
$d = \rtrim($b, '0');
|
|
||||||
$scale = \strlen($b) - \strlen($d);
|
|
||||||
|
|
||||||
$calculator = Calculator::get();
|
|
||||||
|
|
||||||
foreach ([5, 2] as $prime) {
|
|
||||||
for (;;) {
|
|
||||||
$lastDigit = (int) $d[-1];
|
|
||||||
|
|
||||||
if ($lastDigit % $prime !== 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$d = $calculator->divQ($d, (string) $prime);
|
|
||||||
$scale++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->dividedBy($that, $scale)->stripTrailingZeros();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns this number exponentiated to the given value.
|
|
||||||
*
|
|
||||||
* The result has a scale of `$this->scale * $exponent`.
|
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000.
|
|
||||||
*/
|
|
||||||
public function power(int $exponent) : BigDecimal
|
|
||||||
{
|
|
||||||
if ($exponent === 0) {
|
|
||||||
return BigDecimal::one();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($exponent === 1) {
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($exponent < 0 || $exponent > Calculator::MAX_POWER) {
|
|
||||||
throw new \InvalidArgumentException(\sprintf(
|
|
||||||
'The exponent %d is not in the range 0 to %d.',
|
|
||||||
$exponent,
|
|
||||||
Calculator::MAX_POWER
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BigDecimal(Calculator::get()->pow($this->value, $exponent), $this->scale * $exponent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the quotient of the division of this number by the given one.
|
|
||||||
*
|
|
||||||
* The quotient has a scale of `0`.
|
|
||||||
*
|
|
||||||
* @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal.
|
|
||||||
*
|
|
||||||
* @throws MathException If the divisor is not a valid decimal number, or is zero.
|
|
||||||
*/
|
|
||||||
public function quotient(BigNumber|int|float|string $that) : BigDecimal
|
|
||||||
{
|
|
||||||
$that = BigDecimal::of($that);
|
|
||||||
|
|
||||||
if ($that->isZero()) {
|
|
||||||
throw DivisionByZeroException::divisionByZero();
|
|
||||||
}
|
|
||||||
|
|
||||||
$p = $this->valueWithMinScale($that->scale);
|
|
||||||
$q = $that->valueWithMinScale($this->scale);
|
|
||||||
|
|
||||||
$quotient = Calculator::get()->divQ($p, $q);
|
|
||||||
|
|
||||||
return new BigDecimal($quotient, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the remainder of the division of this number by the given one.
|
|
||||||
*
|
|
||||||
* The remainder has a scale of `max($this->scale, $that->scale)`.
|
|
||||||
*
|
|
||||||
* @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal.
|
|
||||||
*
|
|
||||||
* @throws MathException If the divisor is not a valid decimal number, or is zero.
|
|
||||||
*/
|
|
||||||
public function remainder(BigNumber|int|float|string $that) : BigDecimal
|
|
||||||
{
|
|
||||||
$that = BigDecimal::of($that);
|
|
||||||
|
|
||||||
if ($that->isZero()) {
|
|
||||||
throw DivisionByZeroException::divisionByZero();
|
|
||||||
}
|
|
||||||
|
|
||||||
$p = $this->valueWithMinScale($that->scale);
|
|
||||||
$q = $that->valueWithMinScale($this->scale);
|
|
||||||
|
|
||||||
$remainder = Calculator::get()->divR($p, $q);
|
|
||||||
|
|
||||||
$scale = $this->scale > $that->scale ? $this->scale : $that->scale;
|
|
||||||
|
|
||||||
return new BigDecimal($remainder, $scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the quotient and remainder of the division of this number by the given one.
|
|
||||||
*
|
|
||||||
* The quotient has a scale of `0`, and the remainder has a scale of `max($this->scale, $that->scale)`.
|
|
||||||
*
|
|
||||||
* @param BigNumber|int|float|string $that The divisor. Must be convertible to a BigDecimal.
|
|
||||||
*
|
|
||||||
* @return BigDecimal[] An array containing the quotient and the remainder.
|
|
||||||
*
|
|
||||||
* @psalm-return array{BigDecimal, BigDecimal}
|
|
||||||
*
|
|
||||||
* @throws MathException If the divisor is not a valid decimal number, or is zero.
|
|
||||||
*/
|
|
||||||
public function quotientAndRemainder(BigNumber|int|float|string $that) : array
|
|
||||||
{
|
|
||||||
$that = BigDecimal::of($that);
|
|
||||||
|
|
||||||
if ($that->isZero()) {
|
|
||||||
throw DivisionByZeroException::divisionByZero();
|
|
||||||
}
|
|
||||||
|
|
||||||
$p = $this->valueWithMinScale($that->scale);
|
|
||||||
$q = $that->valueWithMinScale($this->scale);
|
|
||||||
|
|
||||||
[$quotient, $remainder] = Calculator::get()->divQR($p, $q);
|
|
||||||
|
|
||||||
$scale = $this->scale > $that->scale ? $this->scale : $that->scale;
|
|
||||||
|
|
||||||
$quotient = new BigDecimal($quotient, 0);
|
|
||||||
$remainder = new BigDecimal($remainder, $scale);
|
|
||||||
|
|
||||||
return [$quotient, $remainder];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the square root of this number, rounded down to the given number of decimals.
|
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException If the scale is negative.
|
|
||||||
* @throws NegativeNumberException If this number is negative.
|
|
||||||
*/
|
|
||||||
public function sqrt(int $scale) : BigDecimal
|
|
||||||
{
|
|
||||||
if ($scale < 0) {
|
|
||||||
throw new \InvalidArgumentException('Scale cannot be negative.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->value === '0') {
|
|
||||||
return new BigDecimal('0', $scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->value[0] === '-') {
|
|
||||||
throw new NegativeNumberException('Cannot calculate the square root of a negative number.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$value = $this->value;
|
|
||||||
$addDigits = 2 * $scale - $this->scale;
|
|
||||||
|
|
||||||
if ($addDigits > 0) {
|
|
||||||
// add zeros
|
|
||||||
$value .= \str_repeat('0', $addDigits);
|
|
||||||
} elseif ($addDigits < 0) {
|
|
||||||
// trim digits
|
|
||||||
if (-$addDigits >= \strlen($this->value)) {
|
|
||||||
// requesting a scale too low, will always yield a zero result
|
|
||||||
return new BigDecimal('0', $scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
$value = \substr($value, 0, $addDigits);
|
|
||||||
}
|
|
||||||
|
|
||||||
$value = Calculator::get()->sqrt($value);
|
|
||||||
|
|
||||||
return new BigDecimal($value, $scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a copy of this BigDecimal with the decimal point moved $n places to the left.
|
|
||||||
*/
|
|
||||||
public function withPointMovedLeft(int $n) : BigDecimal
|
|
||||||
{
|
|
||||||
if ($n === 0) {
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($n < 0) {
|
|
||||||
return $this->withPointMovedRight(-$n);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BigDecimal($this->value, $this->scale + $n);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a copy of this BigDecimal with the decimal point moved $n places to the right.
|
|
||||||
*/
|
|
||||||
public function withPointMovedRight(int $n) : BigDecimal
|
|
||||||
{
|
|
||||||
if ($n === 0) {
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($n < 0) {
|
|
||||||
return $this->withPointMovedLeft(-$n);
|
|
||||||
}
|
|
||||||
|
|
||||||
$value = $this->value;
|
|
||||||
$scale = $this->scale - $n;
|
|
||||||
|
|
||||||
if ($scale < 0) {
|
|
||||||
if ($value !== '0') {
|
|
||||||
$value .= \str_repeat('0', -$scale);
|
|
||||||
}
|
|
||||||
$scale = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BigDecimal($value, $scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a copy of this BigDecimal with any trailing zeros removed from the fractional part.
|
|
||||||
*/
|
|
||||||
public function stripTrailingZeros() : BigDecimal
|
|
||||||
{
|
|
||||||
if ($this->scale === 0) {
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
$trimmedValue = \rtrim($this->value, '0');
|
|
||||||
|
|
||||||
if ($trimmedValue === '') {
|
|
||||||
return BigDecimal::zero();
|
|
||||||
}
|
|
||||||
|
|
||||||
$trimmableZeros = \strlen($this->value) - \strlen($trimmedValue);
|
|
||||||
|
|
||||||
if ($trimmableZeros === 0) {
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($trimmableZeros > $this->scale) {
|
|
||||||
$trimmableZeros = $this->scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
$value = \substr($this->value, 0, -$trimmableZeros);
|
|
||||||
$scale = $this->scale - $trimmableZeros;
|
|
||||||
|
|
||||||
return new BigDecimal($value, $scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the absolute value of this number.
|
|
||||||
*/
|
|
||||||
public function abs() : BigDecimal
|
|
||||||
{
|
|
||||||
return $this->isNegative() ? $this->negated() : $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the negated value of this number.
|
|
||||||
*/
|
|
||||||
public function negated() : BigDecimal
|
|
||||||
{
|
|
||||||
return new BigDecimal(Calculator::get()->neg($this->value), $this->scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Override]
|
|
||||||
public function compareTo(BigNumber|int|float|string $that) : int
|
|
||||||
{
|
|
||||||
$that = BigNumber::of($that);
|
|
||||||
|
|
||||||
if ($that instanceof BigInteger) {
|
|
||||||
$that = $that->toBigDecimal();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($that instanceof BigDecimal) {
|
|
||||||
[$a, $b] = $this->scaleValues($this, $that);
|
|
||||||
|
|
||||||
return Calculator::get()->cmp($a, $b);
|
|
||||||
}
|
|
||||||
|
|
||||||
return - $that->compareTo($this);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Override]
|
|
||||||
public function getSign() : int
|
|
||||||
{
|
|
||||||
return ($this->value === '0') ? 0 : (($this->value[0] === '-') ? -1 : 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUnscaledValue() : BigInteger
|
|
||||||
{
|
|
||||||
return self::newBigInteger($this->value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getScale() : int
|
|
||||||
{
|
|
||||||
return $this->scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of significant digits in the number.
|
|
||||||
*
|
|
||||||
* This is the number of digits to both sides of the decimal point, stripped of leading zeros.
|
|
||||||
* The sign has no impact on the result.
|
|
||||||
*
|
|
||||||
* Examples:
|
|
||||||
* 0 => 0
|
|
||||||
* 0.0 => 0
|
|
||||||
* 123 => 3
|
|
||||||
* 123.456 => 6
|
|
||||||
* 0.00123 => 3
|
|
||||||
* 0.0012300 => 5
|
|
||||||
*/
|
|
||||||
public function getPrecision(): int
|
|
||||||
{
|
|
||||||
$value = $this->value;
|
|
||||||
|
|
||||||
if ($value === '0') {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$length = \strlen($value);
|
|
||||||
|
|
||||||
return ($value[0] === '-') ? $length - 1 : $length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a string representing the integral part of this decimal number.
|
|
||||||
*
|
|
||||||
* Example: `-123.456` => `-123`.
|
|
||||||
*/
|
|
||||||
public function getIntegralPart() : string
|
|
||||||
{
|
|
||||||
if ($this->scale === 0) {
|
|
||||||
return $this->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
$value = $this->getUnscaledValueWithLeadingZeros();
|
|
||||||
|
|
||||||
return \substr($value, 0, -$this->scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a string representing the fractional part of this decimal number.
|
|
||||||
*
|
|
||||||
* If the scale is zero, an empty string is returned.
|
|
||||||
*
|
|
||||||
* Examples: `-123.456` => '456', `123` => ''.
|
|
||||||
*/
|
|
||||||
public function getFractionalPart() : string
|
|
||||||
{
|
|
||||||
if ($this->scale === 0) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$value = $this->getUnscaledValueWithLeadingZeros();
|
|
||||||
|
|
||||||
return \substr($value, -$this->scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether this decimal number has a non-zero fractional part.
|
|
||||||
*/
|
|
||||||
public function hasNonZeroFractionalPart() : bool
|
|
||||||
{
|
|
||||||
return $this->getFractionalPart() !== \str_repeat('0', $this->scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Override]
|
|
||||||
public function toBigInteger() : BigInteger
|
|
||||||
{
|
|
||||||
$zeroScaleDecimal = $this->scale === 0 ? $this : $this->dividedBy(1, 0);
|
|
||||||
|
|
||||||
return self::newBigInteger($zeroScaleDecimal->value);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Override]
|
|
||||||
public function toBigDecimal() : BigDecimal
|
|
||||||
{
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Override]
|
|
||||||
public function toBigRational() : BigRational
|
|
||||||
{
|
|
||||||
$numerator = self::newBigInteger($this->value);
|
|
||||||
$denominator = self::newBigInteger('1' . \str_repeat('0', $this->scale));
|
|
||||||
|
|
||||||
return self::newBigRational($numerator, $denominator, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Override]
|
|
||||||
public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
|
|
||||||
{
|
|
||||||
if ($scale === $this->scale) {
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->dividedBy(BigDecimal::one(), $scale, $roundingMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Override]
|
|
||||||
public function toInt() : int
|
|
||||||
{
|
|
||||||
return $this->toBigInteger()->toInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Override]
|
|
||||||
public function toFloat() : float
|
|
||||||
{
|
|
||||||
return (float) (string) $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Override]
|
|
||||||
public function __toString() : string
|
|
||||||
{
|
|
||||||
if ($this->scale === 0) {
|
|
||||||
return $this->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
$value = $this->getUnscaledValueWithLeadingZeros();
|
|
||||||
|
|
||||||
return \substr($value, 0, -$this->scale) . '.' . \substr($value, -$this->scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is required for serializing the object and SHOULD NOT be accessed directly.
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
*
|
|
||||||
* @return array{value: string, scale: int}
|
|
||||||
*/
|
|
||||||
public function __serialize(): array
|
|
||||||
{
|
|
||||||
return ['value' => $this->value, 'scale' => $this->scale];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is only here to allow unserializing the object and cannot be accessed directly.
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
* @psalm-suppress RedundantPropertyInitializationCheck
|
|
||||||
*
|
|
||||||
* @param array{value: string, scale: int} $data
|
|
||||||
*
|
|
||||||
* @throws \LogicException
|
|
||||||
*/
|
|
||||||
public function __unserialize(array $data): void
|
|
||||||
{
|
|
||||||
if (isset($this->value)) {
|
|
||||||
throw new \LogicException('__unserialize() is an internal function, it must not be called directly.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->value = $data['value'];
|
|
||||||
$this->scale = $data['scale'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Puts the internal values of the given decimal numbers on the same scale.
|
|
||||||
*
|
|
||||||
* @return array{string, string} The scaled integer values of $x and $y.
|
|
||||||
*/
|
|
||||||
private function scaleValues(BigDecimal $x, BigDecimal $y) : array
|
|
||||||
{
|
|
||||||
$a = $x->value;
|
|
||||||
$b = $y->value;
|
|
||||||
|
|
||||||
if ($b !== '0' && $x->scale > $y->scale) {
|
|
||||||
$b .= \str_repeat('0', $x->scale - $y->scale);
|
|
||||||
} elseif ($a !== '0' && $x->scale < $y->scale) {
|
|
||||||
$a .= \str_repeat('0', $y->scale - $x->scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [$a, $b];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function valueWithMinScale(int $scale) : string
|
|
||||||
{
|
|
||||||
$value = $this->value;
|
|
||||||
|
|
||||||
if ($this->value !== '0' && $scale > $this->scale) {
|
|
||||||
$value .= \str_repeat('0', $scale - $this->scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds leading zeros if necessary to the unscaled value to represent the full decimal number.
|
|
||||||
*/
|
|
||||||
private function getUnscaledValueWithLeadingZeros() : string
|
|
||||||
{
|
|
||||||
$value = $this->value;
|
|
||||||
$targetLength = $this->scale + 1;
|
|
||||||
$negative = ($value[0] === '-');
|
|
||||||
$length = \strlen($value);
|
|
||||||
|
|
||||||
if ($negative) {
|
|
||||||
$length--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($length >= $targetLength) {
|
|
||||||
return $this->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($negative) {
|
|
||||||
$value = \substr($value, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
$value = \str_pad($value, $targetLength, '0', STR_PAD_LEFT);
|
|
||||||
|
|
||||||
if ($negative) {
|
|
||||||
$value = '-' . $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,515 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Brick\Math;
|
|
||||||
|
|
||||||
use Brick\Math\Exception\DivisionByZeroException;
|
|
||||||
use Brick\Math\Exception\MathException;
|
|
||||||
use Brick\Math\Exception\NumberFormatException;
|
|
||||||
use Brick\Math\Exception\RoundingNecessaryException;
|
|
||||||
use Override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Common interface for arbitrary-precision rational numbers.
|
|
||||||
*
|
|
||||||
* @psalm-immutable
|
|
||||||
*/
|
|
||||||
abstract class BigNumber implements \JsonSerializable
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The regular expression used to parse integer or decimal numbers.
|
|
||||||
*/
|
|
||||||
private const PARSE_REGEXP_NUMERICAL =
|
|
||||||
'/^' .
|
|
||||||
'(?<sign>[\-\+])?' .
|
|
||||||
'(?<integral>[0-9]+)?' .
|
|
||||||
'(?<point>\.)?' .
|
|
||||||
'(?<fractional>[0-9]+)?' .
|
|
||||||
'(?:[eE](?<exponent>[\-\+]?[0-9]+))?' .
|
|
||||||
'$/';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The regular expression used to parse rational numbers.
|
|
||||||
*/
|
|
||||||
private const PARSE_REGEXP_RATIONAL =
|
|
||||||
'/^' .
|
|
||||||
'(?<sign>[\-\+])?' .
|
|
||||||
'(?<numerator>[0-9]+)' .
|
|
||||||
'\/?' .
|
|
||||||
'(?<denominator>[0-9]+)' .
|
|
||||||
'$/';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a BigNumber of the given value.
|
|
||||||
*
|
|
||||||
* The concrete return type is dependent on the given value, with the following rules:
|
|
||||||
*
|
|
||||||
* - BigNumber instances are returned as is
|
|
||||||
* - integer numbers are returned as BigInteger
|
|
||||||
* - floating point numbers are converted to a string then parsed as such
|
|
||||||
* - strings containing a `/` character are returned as BigRational
|
|
||||||
* - strings containing a `.` character or using an exponential notation are returned as BigDecimal
|
|
||||||
* - strings containing only digits with an optional leading `+` or `-` sign are returned as BigInteger
|
|
||||||
*
|
|
||||||
* @throws NumberFormatException If the format of the number is not valid.
|
|
||||||
* @throws DivisionByZeroException If the value represents a rational number with a denominator of zero.
|
|
||||||
* @throws RoundingNecessaryException If the value cannot be converted to an instance of the subclass without rounding.
|
|
||||||
*
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
final public static function of(BigNumber|int|float|string $value) : static
|
|
||||||
{
|
|
||||||
$value = self::_of($value);
|
|
||||||
|
|
||||||
if (static::class === BigNumber::class) {
|
|
||||||
// https://github.com/vimeo/psalm/issues/10309
|
|
||||||
assert($value instanceof static);
|
|
||||||
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return static::from($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws NumberFormatException If the format of the number is not valid.
|
|
||||||
* @throws DivisionByZeroException If the value represents a rational number with a denominator of zero.
|
|
||||||
*
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
private static function _of(BigNumber|int|float|string $value) : BigNumber
|
|
||||||
{
|
|
||||||
if ($value instanceof BigNumber) {
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (\is_int($value)) {
|
|
||||||
return new BigInteger((string) $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_float($value)) {
|
|
||||||
$value = (string) $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (str_contains($value, '/')) {
|
|
||||||
// Rational number
|
|
||||||
if (\preg_match(self::PARSE_REGEXP_RATIONAL, $value, $matches, PREG_UNMATCHED_AS_NULL) !== 1) {
|
|
||||||
throw NumberFormatException::invalidFormat($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
$sign = $matches['sign'];
|
|
||||||
$numerator = $matches['numerator'];
|
|
||||||
$denominator = $matches['denominator'];
|
|
||||||
|
|
||||||
assert($numerator !== null);
|
|
||||||
assert($denominator !== null);
|
|
||||||
|
|
||||||
$numerator = self::cleanUp($sign, $numerator);
|
|
||||||
$denominator = self::cleanUp(null, $denominator);
|
|
||||||
|
|
||||||
if ($denominator === '0') {
|
|
||||||
throw DivisionByZeroException::denominatorMustNotBeZero();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BigRational(
|
|
||||||
new BigInteger($numerator),
|
|
||||||
new BigInteger($denominator),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Integer or decimal number
|
|
||||||
if (\preg_match(self::PARSE_REGEXP_NUMERICAL, $value, $matches, PREG_UNMATCHED_AS_NULL) !== 1) {
|
|
||||||
throw NumberFormatException::invalidFormat($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
$sign = $matches['sign'];
|
|
||||||
$point = $matches['point'];
|
|
||||||
$integral = $matches['integral'];
|
|
||||||
$fractional = $matches['fractional'];
|
|
||||||
$exponent = $matches['exponent'];
|
|
||||||
|
|
||||||
if ($integral === null && $fractional === null) {
|
|
||||||
throw NumberFormatException::invalidFormat($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($integral === null) {
|
|
||||||
$integral = '0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($point !== null || $exponent !== null) {
|
|
||||||
$fractional = ($fractional ?? '');
|
|
||||||
$exponent = ($exponent !== null) ? (int)$exponent : 0;
|
|
||||||
|
|
||||||
if ($exponent === PHP_INT_MIN || $exponent === PHP_INT_MAX) {
|
|
||||||
throw new NumberFormatException('Exponent too large.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$unscaledValue = self::cleanUp($sign, $integral . $fractional);
|
|
||||||
|
|
||||||
$scale = \strlen($fractional) - $exponent;
|
|
||||||
|
|
||||||
if ($scale < 0) {
|
|
||||||
if ($unscaledValue !== '0') {
|
|
||||||
$unscaledValue .= \str_repeat('0', -$scale);
|
|
||||||
}
|
|
||||||
$scale = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BigDecimal($unscaledValue, $scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
$integral = self::cleanUp($sign, $integral);
|
|
||||||
|
|
||||||
return new BigInteger($integral);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overridden by subclasses to convert a BigNumber to an instance of the subclass.
|
|
||||||
*
|
|
||||||
* @throws RoundingNecessaryException If the value cannot be converted.
|
|
||||||
*
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
abstract protected static function from(BigNumber $number): static;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Proxy method to access BigInteger's protected constructor from sibling classes.
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
final protected function newBigInteger(string $value) : BigInteger
|
|
||||||
{
|
|
||||||
return new BigInteger($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Proxy method to access BigDecimal's protected constructor from sibling classes.
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
final protected function newBigDecimal(string $value, int $scale = 0) : BigDecimal
|
|
||||||
{
|
|
||||||
return new BigDecimal($value, $scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Proxy method to access BigRational's protected constructor from sibling classes.
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
final protected function newBigRational(BigInteger $numerator, BigInteger $denominator, bool $checkDenominator) : BigRational
|
|
||||||
{
|
|
||||||
return new BigRational($numerator, $denominator, $checkDenominator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the minimum of the given values.
|
|
||||||
*
|
|
||||||
* @param BigNumber|int|float|string ...$values The numbers to compare. All the numbers need to be convertible
|
|
||||||
* to an instance of the class this method is called on.
|
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException If no values are given.
|
|
||||||
* @throws MathException If an argument is not valid.
|
|
||||||
*
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
final public static function min(BigNumber|int|float|string ...$values) : static
|
|
||||||
{
|
|
||||||
$min = null;
|
|
||||||
|
|
||||||
foreach ($values as $value) {
|
|
||||||
$value = static::of($value);
|
|
||||||
|
|
||||||
if ($min === null || $value->isLessThan($min)) {
|
|
||||||
$min = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($min === null) {
|
|
||||||
throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $min;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the maximum of the given values.
|
|
||||||
*
|
|
||||||
* @param BigNumber|int|float|string ...$values The numbers to compare. All the numbers need to be convertible
|
|
||||||
* to an instance of the class this method is called on.
|
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException If no values are given.
|
|
||||||
* @throws MathException If an argument is not valid.
|
|
||||||
*
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
final public static function max(BigNumber|int|float|string ...$values) : static
|
|
||||||
{
|
|
||||||
$max = null;
|
|
||||||
|
|
||||||
foreach ($values as $value) {
|
|
||||||
$value = static::of($value);
|
|
||||||
|
|
||||||
if ($max === null || $value->isGreaterThan($max)) {
|
|
||||||
$max = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($max === null) {
|
|
||||||
throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $max;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the sum of the given values.
|
|
||||||
*
|
|
||||||
* @param BigNumber|int|float|string ...$values The numbers to add. All the numbers need to be convertible
|
|
||||||
* to an instance of the class this method is called on.
|
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException If no values are given.
|
|
||||||
* @throws MathException If an argument is not valid.
|
|
||||||
*
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
final public static function sum(BigNumber|int|float|string ...$values) : static
|
|
||||||
{
|
|
||||||
/** @var static|null $sum */
|
|
||||||
$sum = null;
|
|
||||||
|
|
||||||
foreach ($values as $value) {
|
|
||||||
$value = static::of($value);
|
|
||||||
|
|
||||||
$sum = $sum === null ? $value : self::add($sum, $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($sum === null) {
|
|
||||||
throw new \InvalidArgumentException(__METHOD__ . '() expects at least one value.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds two BigNumber instances in the correct order to avoid a RoundingNecessaryException.
|
|
||||||
*
|
|
||||||
* @todo This could be better resolved by creating an abstract protected method in BigNumber, and leaving to
|
|
||||||
* concrete classes the responsibility to perform the addition themselves or delegate it to the given number,
|
|
||||||
* depending on their ability to perform the operation. This will also require a version bump because we're
|
|
||||||
* potentially breaking custom BigNumber implementations (if any...)
|
|
||||||
*
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
private static function add(BigNumber $a, BigNumber $b) : BigNumber
|
|
||||||
{
|
|
||||||
if ($a instanceof BigRational) {
|
|
||||||
return $a->plus($b);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($b instanceof BigRational) {
|
|
||||||
return $b->plus($a);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($a instanceof BigDecimal) {
|
|
||||||
return $a->plus($b);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($b instanceof BigDecimal) {
|
|
||||||
return $b->plus($a);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var BigInteger $a */
|
|
||||||
|
|
||||||
return $a->plus($b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes optional leading zeros and applies sign.
|
|
||||||
*
|
|
||||||
* @param string|null $sign The sign, '+' or '-', optional. Null is allowed for convenience and treated as '+'.
|
|
||||||
* @param string $number The number, validated as a non-empty string of digits.
|
|
||||||
*
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
private static function cleanUp(string|null $sign, string $number) : string
|
|
||||||
{
|
|
||||||
$number = \ltrim($number, '0');
|
|
||||||
|
|
||||||
if ($number === '') {
|
|
||||||
return '0';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $sign === '-' ? '-' . $number : $number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if this number is equal to the given one.
|
|
||||||
*/
|
|
||||||
final public function isEqualTo(BigNumber|int|float|string $that) : bool
|
|
||||||
{
|
|
||||||
return $this->compareTo($that) === 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if this number is strictly lower than the given one.
|
|
||||||
*/
|
|
||||||
final public function isLessThan(BigNumber|int|float|string $that) : bool
|
|
||||||
{
|
|
||||||
return $this->compareTo($that) < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if this number is lower than or equal to the given one.
|
|
||||||
*/
|
|
||||||
final public function isLessThanOrEqualTo(BigNumber|int|float|string $that) : bool
|
|
||||||
{
|
|
||||||
return $this->compareTo($that) <= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if this number is strictly greater than the given one.
|
|
||||||
*/
|
|
||||||
final public function isGreaterThan(BigNumber|int|float|string $that) : bool
|
|
||||||
{
|
|
||||||
return $this->compareTo($that) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if this number is greater than or equal to the given one.
|
|
||||||
*/
|
|
||||||
final public function isGreaterThanOrEqualTo(BigNumber|int|float|string $that) : bool
|
|
||||||
{
|
|
||||||
return $this->compareTo($that) >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if this number equals zero.
|
|
||||||
*/
|
|
||||||
final public function isZero() : bool
|
|
||||||
{
|
|
||||||
return $this->getSign() === 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if this number is strictly negative.
|
|
||||||
*/
|
|
||||||
final public function isNegative() : bool
|
|
||||||
{
|
|
||||||
return $this->getSign() < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if this number is negative or zero.
|
|
||||||
*/
|
|
||||||
final public function isNegativeOrZero() : bool
|
|
||||||
{
|
|
||||||
return $this->getSign() <= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if this number is strictly positive.
|
|
||||||
*/
|
|
||||||
final public function isPositive() : bool
|
|
||||||
{
|
|
||||||
return $this->getSign() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if this number is positive or zero.
|
|
||||||
*/
|
|
||||||
final public function isPositiveOrZero() : bool
|
|
||||||
{
|
|
||||||
return $this->getSign() >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the sign of this number.
|
|
||||||
*
|
|
||||||
* @psalm-return -1|0|1
|
|
||||||
*
|
|
||||||
* @return int -1 if the number is negative, 0 if zero, 1 if positive.
|
|
||||||
*/
|
|
||||||
abstract public function getSign() : int;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compares this number to the given one.
|
|
||||||
*
|
|
||||||
* @psalm-return -1|0|1
|
|
||||||
*
|
|
||||||
* @return int -1 if `$this` is lower than, 0 if equal to, 1 if greater than `$that`.
|
|
||||||
*
|
|
||||||
* @throws MathException If the number is not valid.
|
|
||||||
*/
|
|
||||||
abstract public function compareTo(BigNumber|int|float|string $that) : int;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts this number to a BigInteger.
|
|
||||||
*
|
|
||||||
* @throws RoundingNecessaryException If this number cannot be converted to a BigInteger without rounding.
|
|
||||||
*/
|
|
||||||
abstract public function toBigInteger() : BigInteger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts this number to a BigDecimal.
|
|
||||||
*
|
|
||||||
* @throws RoundingNecessaryException If this number cannot be converted to a BigDecimal without rounding.
|
|
||||||
*/
|
|
||||||
abstract public function toBigDecimal() : BigDecimal;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts this number to a BigRational.
|
|
||||||
*/
|
|
||||||
abstract public function toBigRational() : BigRational;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts this number to a BigDecimal with the given scale, using rounding if necessary.
|
|
||||||
*
|
|
||||||
* @param int $scale The scale of the resulting `BigDecimal`.
|
|
||||||
* @param RoundingMode $roundingMode An optional rounding mode, defaults to UNNECESSARY.
|
|
||||||
*
|
|
||||||
* @throws RoundingNecessaryException If this number cannot be converted to the given scale without rounding.
|
|
||||||
* This only applies when RoundingMode::UNNECESSARY is used.
|
|
||||||
*/
|
|
||||||
abstract public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the exact value of this number as a native integer.
|
|
||||||
*
|
|
||||||
* If this number cannot be converted to a native integer without losing precision, an exception is thrown.
|
|
||||||
* Note that the acceptable range for an integer depends on the platform and differs for 32-bit and 64-bit.
|
|
||||||
*
|
|
||||||
* @throws MathException If this number cannot be exactly converted to a native integer.
|
|
||||||
*/
|
|
||||||
abstract public function toInt() : int;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an approximation of this number as a floating-point value.
|
|
||||||
*
|
|
||||||
* Note that this method can discard information as the precision of a floating-point value
|
|
||||||
* is inherently limited.
|
|
||||||
*
|
|
||||||
* If the number is greater than the largest representable floating point number, positive infinity is returned.
|
|
||||||
* If the number is less than the smallest representable floating point number, negative infinity is returned.
|
|
||||||
*/
|
|
||||||
abstract public function toFloat() : float;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a string representation of this number.
|
|
||||||
*
|
|
||||||
* The output of this method can be parsed by the `of()` factory method;
|
|
||||||
* this will yield an object equal to this one, without any information loss.
|
|
||||||
*/
|
|
||||||
abstract public function __toString() : string;
|
|
||||||
|
|
||||||
#[Override]
|
|
||||||
final public function jsonSerialize() : string
|
|
||||||
{
|
|
||||||
return $this->__toString();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,424 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Brick\Math;
|
|
||||||
|
|
||||||
use Brick\Math\Exception\DivisionByZeroException;
|
|
||||||
use Brick\Math\Exception\MathException;
|
|
||||||
use Brick\Math\Exception\NumberFormatException;
|
|
||||||
use Brick\Math\Exception\RoundingNecessaryException;
|
|
||||||
use Override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An arbitrarily large rational number.
|
|
||||||
*
|
|
||||||
* This class is immutable.
|
|
||||||
*
|
|
||||||
* @psalm-immutable
|
|
||||||
*/
|
|
||||||
final class BigRational extends BigNumber
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The numerator.
|
|
||||||
*/
|
|
||||||
private readonly BigInteger $numerator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The denominator. Always strictly positive.
|
|
||||||
*/
|
|
||||||
private readonly BigInteger $denominator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Protected constructor. Use a factory method to obtain an instance.
|
|
||||||
*
|
|
||||||
* @param BigInteger $numerator The numerator.
|
|
||||||
* @param BigInteger $denominator The denominator.
|
|
||||||
* @param bool $checkDenominator Whether to check the denominator for negative and zero.
|
|
||||||
*
|
|
||||||
* @throws DivisionByZeroException If the denominator is zero.
|
|
||||||
*/
|
|
||||||
protected function __construct(BigInteger $numerator, BigInteger $denominator, bool $checkDenominator)
|
|
||||||
{
|
|
||||||
if ($checkDenominator) {
|
|
||||||
if ($denominator->isZero()) {
|
|
||||||
throw DivisionByZeroException::denominatorMustNotBeZero();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($denominator->isNegative()) {
|
|
||||||
$numerator = $numerator->negated();
|
|
||||||
$denominator = $denominator->negated();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->numerator = $numerator;
|
|
||||||
$this->denominator = $denominator;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
#[Override]
|
|
||||||
protected static function from(BigNumber $number): static
|
|
||||||
{
|
|
||||||
return $number->toBigRational();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a BigRational out of a numerator and a denominator.
|
|
||||||
*
|
|
||||||
* If the denominator is negative, the signs of both the numerator and the denominator
|
|
||||||
* will be inverted to ensure that the denominator is always positive.
|
|
||||||
*
|
|
||||||
* @param BigNumber|int|float|string $numerator The numerator. Must be convertible to a BigInteger.
|
|
||||||
* @param BigNumber|int|float|string $denominator The denominator. Must be convertible to a BigInteger.
|
|
||||||
*
|
|
||||||
* @throws NumberFormatException If an argument does not represent a valid number.
|
|
||||||
* @throws RoundingNecessaryException If an argument represents a non-integer number.
|
|
||||||
* @throws DivisionByZeroException If the denominator is zero.
|
|
||||||
*
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
public static function nd(
|
|
||||||
BigNumber|int|float|string $numerator,
|
|
||||||
BigNumber|int|float|string $denominator,
|
|
||||||
) : BigRational {
|
|
||||||
$numerator = BigInteger::of($numerator);
|
|
||||||
$denominator = BigInteger::of($denominator);
|
|
||||||
|
|
||||||
return new BigRational($numerator, $denominator, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a BigRational representing zero.
|
|
||||||
*
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
public static function zero() : BigRational
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @psalm-suppress ImpureStaticVariable
|
|
||||||
* @var BigRational|null $zero
|
|
||||||
*/
|
|
||||||
static $zero;
|
|
||||||
|
|
||||||
if ($zero === null) {
|
|
||||||
$zero = new BigRational(BigInteger::zero(), BigInteger::one(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $zero;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a BigRational representing one.
|
|
||||||
*
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
public static function one() : BigRational
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @psalm-suppress ImpureStaticVariable
|
|
||||||
* @var BigRational|null $one
|
|
||||||
*/
|
|
||||||
static $one;
|
|
||||||
|
|
||||||
if ($one === null) {
|
|
||||||
$one = new BigRational(BigInteger::one(), BigInteger::one(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $one;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a BigRational representing ten.
|
|
||||||
*
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
public static function ten() : BigRational
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @psalm-suppress ImpureStaticVariable
|
|
||||||
* @var BigRational|null $ten
|
|
||||||
*/
|
|
||||||
static $ten;
|
|
||||||
|
|
||||||
if ($ten === null) {
|
|
||||||
$ten = new BigRational(BigInteger::ten(), BigInteger::one(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $ten;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getNumerator() : BigInteger
|
|
||||||
{
|
|
||||||
return $this->numerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDenominator() : BigInteger
|
|
||||||
{
|
|
||||||
return $this->denominator;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the quotient of the division of the numerator by the denominator.
|
|
||||||
*/
|
|
||||||
public function quotient() : BigInteger
|
|
||||||
{
|
|
||||||
return $this->numerator->quotient($this->denominator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the remainder of the division of the numerator by the denominator.
|
|
||||||
*/
|
|
||||||
public function remainder() : BigInteger
|
|
||||||
{
|
|
||||||
return $this->numerator->remainder($this->denominator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the quotient and remainder of the division of the numerator by the denominator.
|
|
||||||
*
|
|
||||||
* @return BigInteger[]
|
|
||||||
*
|
|
||||||
* @psalm-return array{BigInteger, BigInteger}
|
|
||||||
*/
|
|
||||||
public function quotientAndRemainder() : array
|
|
||||||
{
|
|
||||||
return $this->numerator->quotientAndRemainder($this->denominator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the sum of this number and the given one.
|
|
||||||
*
|
|
||||||
* @param BigNumber|int|float|string $that The number to add.
|
|
||||||
*
|
|
||||||
* @throws MathException If the number is not valid.
|
|
||||||
*/
|
|
||||||
public function plus(BigNumber|int|float|string $that) : BigRational
|
|
||||||
{
|
|
||||||
$that = BigRational::of($that);
|
|
||||||
|
|
||||||
$numerator = $this->numerator->multipliedBy($that->denominator);
|
|
||||||
$numerator = $numerator->plus($that->numerator->multipliedBy($this->denominator));
|
|
||||||
$denominator = $this->denominator->multipliedBy($that->denominator);
|
|
||||||
|
|
||||||
return new BigRational($numerator, $denominator, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the difference of this number and the given one.
|
|
||||||
*
|
|
||||||
* @param BigNumber|int|float|string $that The number to subtract.
|
|
||||||
*
|
|
||||||
* @throws MathException If the number is not valid.
|
|
||||||
*/
|
|
||||||
public function minus(BigNumber|int|float|string $that) : BigRational
|
|
||||||
{
|
|
||||||
$that = BigRational::of($that);
|
|
||||||
|
|
||||||
$numerator = $this->numerator->multipliedBy($that->denominator);
|
|
||||||
$numerator = $numerator->minus($that->numerator->multipliedBy($this->denominator));
|
|
||||||
$denominator = $this->denominator->multipliedBy($that->denominator);
|
|
||||||
|
|
||||||
return new BigRational($numerator, $denominator, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the product of this number and the given one.
|
|
||||||
*
|
|
||||||
* @param BigNumber|int|float|string $that The multiplier.
|
|
||||||
*
|
|
||||||
* @throws MathException If the multiplier is not a valid number.
|
|
||||||
*/
|
|
||||||
public function multipliedBy(BigNumber|int|float|string $that) : BigRational
|
|
||||||
{
|
|
||||||
$that = BigRational::of($that);
|
|
||||||
|
|
||||||
$numerator = $this->numerator->multipliedBy($that->numerator);
|
|
||||||
$denominator = $this->denominator->multipliedBy($that->denominator);
|
|
||||||
|
|
||||||
return new BigRational($numerator, $denominator, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the result of the division of this number by the given one.
|
|
||||||
*
|
|
||||||
* @param BigNumber|int|float|string $that The divisor.
|
|
||||||
*
|
|
||||||
* @throws MathException If the divisor is not a valid number, or is zero.
|
|
||||||
*/
|
|
||||||
public function dividedBy(BigNumber|int|float|string $that) : BigRational
|
|
||||||
{
|
|
||||||
$that = BigRational::of($that);
|
|
||||||
|
|
||||||
$numerator = $this->numerator->multipliedBy($that->denominator);
|
|
||||||
$denominator = $this->denominator->multipliedBy($that->numerator);
|
|
||||||
|
|
||||||
return new BigRational($numerator, $denominator, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns this number exponentiated to the given value.
|
|
||||||
*
|
|
||||||
* @throws \InvalidArgumentException If the exponent is not in the range 0 to 1,000,000.
|
|
||||||
*/
|
|
||||||
public function power(int $exponent) : BigRational
|
|
||||||
{
|
|
||||||
if ($exponent === 0) {
|
|
||||||
$one = BigInteger::one();
|
|
||||||
|
|
||||||
return new BigRational($one, $one, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($exponent === 1) {
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BigRational(
|
|
||||||
$this->numerator->power($exponent),
|
|
||||||
$this->denominator->power($exponent),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the reciprocal of this BigRational.
|
|
||||||
*
|
|
||||||
* The reciprocal has the numerator and denominator swapped.
|
|
||||||
*
|
|
||||||
* @throws DivisionByZeroException If the numerator is zero.
|
|
||||||
*/
|
|
||||||
public function reciprocal() : BigRational
|
|
||||||
{
|
|
||||||
return new BigRational($this->denominator, $this->numerator, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the absolute value of this BigRational.
|
|
||||||
*/
|
|
||||||
public function abs() : BigRational
|
|
||||||
{
|
|
||||||
return new BigRational($this->numerator->abs(), $this->denominator, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the negated value of this BigRational.
|
|
||||||
*/
|
|
||||||
public function negated() : BigRational
|
|
||||||
{
|
|
||||||
return new BigRational($this->numerator->negated(), $this->denominator, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the simplified value of this BigRational.
|
|
||||||
*/
|
|
||||||
public function simplified() : BigRational
|
|
||||||
{
|
|
||||||
$gcd = $this->numerator->gcd($this->denominator);
|
|
||||||
|
|
||||||
$numerator = $this->numerator->quotient($gcd);
|
|
||||||
$denominator = $this->denominator->quotient($gcd);
|
|
||||||
|
|
||||||
return new BigRational($numerator, $denominator, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Override]
|
|
||||||
public function compareTo(BigNumber|int|float|string $that) : int
|
|
||||||
{
|
|
||||||
return $this->minus($that)->getSign();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Override]
|
|
||||||
public function getSign() : int
|
|
||||||
{
|
|
||||||
return $this->numerator->getSign();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Override]
|
|
||||||
public function toBigInteger() : BigInteger
|
|
||||||
{
|
|
||||||
$simplified = $this->simplified();
|
|
||||||
|
|
||||||
if (! $simplified->denominator->isEqualTo(1)) {
|
|
||||||
throw new RoundingNecessaryException('This rational number cannot be represented as an integer value without rounding.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $simplified->numerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Override]
|
|
||||||
public function toBigDecimal() : BigDecimal
|
|
||||||
{
|
|
||||||
return $this->numerator->toBigDecimal()->exactlyDividedBy($this->denominator);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Override]
|
|
||||||
public function toBigRational() : BigRational
|
|
||||||
{
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Override]
|
|
||||||
public function toScale(int $scale, RoundingMode $roundingMode = RoundingMode::UNNECESSARY) : BigDecimal
|
|
||||||
{
|
|
||||||
return $this->numerator->toBigDecimal()->dividedBy($this->denominator, $scale, $roundingMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Override]
|
|
||||||
public function toInt() : int
|
|
||||||
{
|
|
||||||
return $this->toBigInteger()->toInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Override]
|
|
||||||
public function toFloat() : float
|
|
||||||
{
|
|
||||||
$simplified = $this->simplified();
|
|
||||||
return $simplified->numerator->toFloat() / $simplified->denominator->toFloat();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Override]
|
|
||||||
public function __toString() : string
|
|
||||||
{
|
|
||||||
$numerator = (string) $this->numerator;
|
|
||||||
$denominator = (string) $this->denominator;
|
|
||||||
|
|
||||||
if ($denominator === '1') {
|
|
||||||
return $numerator;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $numerator . '/' . $denominator;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is required for serializing the object and SHOULD NOT be accessed directly.
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
*
|
|
||||||
* @return array{numerator: BigInteger, denominator: BigInteger}
|
|
||||||
*/
|
|
||||||
public function __serialize(): array
|
|
||||||
{
|
|
||||||
return ['numerator' => $this->numerator, 'denominator' => $this->denominator];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is only here to allow unserializing the object and cannot be accessed directly.
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
* @psalm-suppress RedundantPropertyInitializationCheck
|
|
||||||
*
|
|
||||||
* @param array{numerator: BigInteger, denominator: BigInteger} $data
|
|
||||||
*
|
|
||||||
* @throws \LogicException
|
|
||||||
*/
|
|
||||||
public function __unserialize(array $data): void
|
|
||||||
{
|
|
||||||
if (isset($this->numerator)) {
|
|
||||||
throw new \LogicException('__unserialize() is an internal function, it must not be called directly.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->numerator = $data['numerator'];
|
|
||||||
$this->denominator = $data['denominator'];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Brick\Math\Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception thrown when a division by zero occurs.
|
|
||||||
*/
|
|
||||||
class DivisionByZeroException extends MathException
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
public static function divisionByZero() : DivisionByZeroException
|
|
||||||
{
|
|
||||||
return new self('Division by zero.');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
public static function modulusMustNotBeZero() : DivisionByZeroException
|
|
||||||
{
|
|
||||||
return new self('The modulus must not be zero.');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
public static function denominatorMustNotBeZero() : DivisionByZeroException
|
|
||||||
{
|
|
||||||
return new self('The denominator of a rational number cannot be zero.');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Brick\Math\Exception;
|
|
||||||
|
|
||||||
use Brick\Math\BigInteger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception thrown when an integer overflow occurs.
|
|
||||||
*/
|
|
||||||
class IntegerOverflowException extends MathException
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @psalm-pure
|
|
||||||
*/
|
|
||||||
public static function toIntOverflow(BigInteger $value) : IntegerOverflowException
|
|
||||||
{
|
|
||||||
$message = '%s is out of range %d to %d and cannot be represented as an integer.';
|
|
||||||
|
|
||||||
return new self(\sprintf($message, (string) $value, PHP_INT_MIN, PHP_INT_MAX));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Brick\Math\Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for all math exceptions.
|
|
||||||
*/
|
|
||||||
class MathException extends \Exception
|
|
||||||
{
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue