Ir para conteúdo
Fórum Script Brasil

Frank K Hosaka

Membros
  • Total de itens

    1.622
  • Registro em

  • Última visita

Tudo que Frank K Hosaka postou

  1. Hoje eu perdi um tempo danado para testar o código, esqueci de ativar o Tailwinds no terminal do VS Code: npx tailwindcss -i input.css -o output.css --watch Outro problema bem sério é que o Copilot às vezes usa o CSS puro e outras vezes o CSS da Tailwinds. Mesmo assim, eu consegui fazer um modal baseado num arquivo fora do arquivo principal. Mas estou contente com o Copilot, ele me ensinou como mandar uma variável para o modal funcionar. Tive que mudar a classe e outros dois arquivos: arquivo balancete.php <?php class Balancete { function apuracaoSelecionada() { $_SESSION['dia']=$_POST['ano']."-".$_POST['mes']."-01"; return header('location:?Balancete.inicio'); } function inicio($paginaAtual=null) { $maiorAno=(new Conn)->select("max(year(dia)) as maior from tbdiario")[0]->maior; $menorAno=(new Conn)->select("min(year(dia)) as menor from tbdiario")[0]->menor; $anos=[]; for($i=$maiorAno;$i>=$menorAno;$i--) { $anos[]=$i; } $dia = isset($_SESSION['dia']) ? $_SESSION['dia'] : date('Y-m-d'); $vetor=apuracao($dia); $primeiroDia=$vetor->primeiroDia; $ultimoDia=$vetor->ultimoDia; $mesExtenso=$vetor->mesExtenso; $matriz=[]; $registros=(new Conn)->select("count(*) as total from tbconta")[0]->total; $registrosPorPagina=15; $paginaAtual = ($paginaAtual) ? $paginaAtual : 1; $indicador = ($paginaAtual - 1) * $registrosPorPagina; $contas=(new Conn)->select("* from tbconta limit $indicador, $registrosPorPagina"); foreach($contas as $conta) { $debitos=(new Conn)->select("sum(valor) as soma from tbdiario where contad=$conta->conta and dia < '$primeiroDia'")[0]->soma; $creditos=(new Conn)->select("sum(valor) as soma from tbdiario where contac=$conta->conta and dia < '$primeiroDia'")[0]->soma; $inicio=round($debitos-$creditos,2); $debito=(new Conn)->select("sum(valor) as soma from tbdiario where contad=$conta->conta and dia between '$primeiroDia' and '$ultimoDia'")[0]->soma; $credito=(new Conn)->select("sum(valor) as soma from tbdiario where contac=$conta->conta and dia between '$primeiroDia' and '$ultimoDia'")[0]->soma; $saldo=$inicio+$debito-$credito; $matriz[]=['conta'=>$conta->conta,'descricao'=>$conta->descricao, 'inicio'=>$inicio,'debito'=>$debito,'credito'=>$credito, 'saldo'=>$saldo]; } $jMatriz=json_decode(json_encode($matriz)); return view('balanceteView',['jMatriz'=>$jMatriz,'paginaAtual'=>$paginaAtual, 'mesExtenso'=>$mesExtenso,'anos'=>$anos]); } } arquivo balanceteApuracao.php <?php if(isset($_GET['anos'])){$anos=json_decode($_GET['anos']);} ?> <div class="fixed w-full max-w-[500px] mx-auto sm:w-[500px] text-center mb-4"> <div>Escolha o ano</div> <form method="post" action="?Balancete.apuracaoSelecionada"> <div> <select name="ano" class="bg-blue-600 shadow appearance-none border rounded py-2 px-3 text-white leading-tight focus:outline-none focus:shadow-outline"> <?php foreach($anos as $ano): ?> <option><?=$ano?></option> <?php endforeach; ?> </select> </div> <div class=mt-4>Escolha o mês</div> <div class="grid grid-cols-6 gap-1 max-w-md mx-auto mt-4"> <?php for($i = 1; $i <= 12; $i++): $j = sprintf("%02d", $i); ?> <input type="submit" name="mes" value="<?=$j?>" class="bg-blue-500 text-white py-2 px-4 rounded"> <?php endfor; ?> </div> </form> </div> arquivo balanceteView.php <?php include('menuView.php'); ?> <style> .grid-container { display: grid; grid-template-columns: 260px 150px 150px 150px 125px; /* Colunas com largura fixa */ width: 835px; /* Ajustando explicitamente o tamanho do grid */ margin: 0 auto; /* Centralizando */ } @media (max-width: 768px) { .grid-container { grid-template-columns: 200px 125px; /* Ajuste para 2 colunas */ width: 100%; /* Largura cheia para mobile */ } .grid-container > :nth-child(2), .grid-container > :nth-child(3), .grid-container > :nth-child(4) { display: none; } .truncate { max-width: 200px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } } </style> <script> function abrirModal() { modal.classList.toggle('hidden'); var anos=<?=json_encode($anos)?>; var xhr = new XMLHttpRequest(); var queryString = "?anos=" + encodeURIComponent(JSON.stringify(anos)); xhr.open('GET', 'balanceteApuracao.php' + queryString, true); xhr.onreadystatechange = function () { if (xhr.readyState === 4 && xhr.status === 200) { document.getElementById('modal').innerHTML = xhr.responseText; } }; xhr.send(); } </script> <div id="modal" class="hidden absolute mt-[40px] left-[510px] bg-white bg-opacity-100 w-[500px] h-60 border"> </div> <div class="w-full max-w-[500px] mx-auto sm:w-[500px] text-center mb-4"> <button class="text-blue-500 hover:text-blue-700" onclick=abrirModal()> Balancete de <?=$mesExtenso?></button></div> <div class="bg-gray-100 flex flex-col items-center justify-center w-full mx-auto"> <div class="container mx-auto"> <div class="grid-container bg-gray-800 text-white"> <div class="py-0 text-center truncate">Conta</div> <div class="py-0 text-center">Início</div> <div class="py-0 text-center">Débito</div> <div class="py-0 text-center">Crédito</div> <div class="py-0 text-center">Saldo</div> </div> <?php foreach($jMatriz as $conta): ?> <div class="grid-container bg-white"> <div class="border px-4 py-0 text-left truncate"><?=$conta->conta?> <?=$conta->descricao?></div> <div class="border px-4 py-0 text-right"><?=dec($conta->inicio)?></div> <div class="border px-4 py-0 text-right"><?=dec($conta->debito)?></div> <div class="border px-4 py-0 text-right"><?=dec($conta->credito)?></div> <div class="border px-4 py-0 text-right"><?=dec($conta->saldo)?></div> </div> <?php endforeach; $paginaAnterior=$paginaAtual-1; $paginaAtual++; ?> <div class="flex justify-between w-full max-w-[835px] mt-4 mx-auto"> <a href="?Balancete.inicio.<?=$paginaAnterior?>" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-2 rounded">Anterior</a> <a href="?Balancete.inicio.<?=$paginaAtual?>" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-2 rounded">Próximo</a> </div> </div> </div>
  2. Ontem, o Copilot mostrou para mim que é possível exibir todas as opções do <select></select> através da propriedade size, mas eu fiquei preocupado com o tamanho da tela do celular, então decidi usar 12 <input>. Eu não tive coragem de copiar todos os 12 <input> do Copilot, eu só copiei um <input> e pedi para o PHP criar os outros <input>. Mas ainda sobrou um <select> e pedi para o Copilot azular para mim, mas ele não azulou, ele criou uma caixa de texto azulada como título e a seguir desenhou o <select>. Eu copiei o CSS Tailwinds da caixa de texto e apliquei no <select>. Veja como ficou: arquivo balanceteApuracao.php <?php include('menuView.php'); ?> <div class="w-full max-w-[500px] mx-auto sm:w-[500px] text-center mb-4"> <div>Escolha o ano</div> <form method="post" action="?Balancete.apuracaoSelecionada"> <div> <select name="ano" class="bg-blue-600 shadow appearance-none border rounded py-2 px-3 text-white leading-tight focus:outline-none focus:shadow-outline"> <?php foreach($anos as $ano): ?> <option><?=$ano?></option> <?php endforeach; ?> </select> </div> <div class=mt-4>Escolha o mês</div> <div class="grid grid-cols-6 gap-1 max-w-md mx-auto mt-4"> <?php for($i = 1; $i <= 12; $i++): $j = sprintf("%02d", $i); ?> <input type="submit" name="mes" value="<?=$j?>" class="bg-blue-500 text-white py-2 px-4 rounded"> <?php endfor; ?> </div> </form> </div>
  3. Foi em 1999 é que consegui o meu primeiro computador de bolso, o Palm. O meu sonho era colocar o banco de dados nele, mas o máximo que eu consegui foi colocar uma cópia do banco de dados só para consulta, através do ListToGo e mais tarde o Handbase. Em 2020, eu consegui conectar o Android ao Windows, graças ao WampServe, o PHP, o MySQL e o VS Code. O problema é que a tela do celular é bem pequena se comparado ao notebook, logo não dá para mostrar tudo o que aparece no notebook no celular. O balancete, por exemplo, tem cinco colunas. O celular só tem espaço para uma coluna, e mesmo assim não dá para mostrar tudo. Para resolver isso, só o HTML é que pode resolver, e essa é uma linguagem que eu não sei mexer. Em outubro de 2024, comecei a trabalhar com o Copilot, a Gemini recusou várias vezes de me ajudar, acho que ela não gosta de mim. O código a seguir é praticamente 100% do Copilot, copiei e colei e fiz um pequeno ajuste na posição do rótulo "conta": arquivo balanceteView.php <?php include('menuView.php'); ?> <style> .grid-container { display: grid; grid-template-columns: 260px 150px 150px 150px 125px; /* Colunas com largura fixa */ width: 835px; /* Ajustando explicitamente o tamanho do grid */ margin: 0 auto; /* Centralizando */ } @media (max-width: 768px) { .grid-container { grid-template-columns: 200px 125px; /* Ajuste para 2 colunas */ width: 100%; /* Largura cheia para mobile */ } .grid-container > :nth-child(2), .grid-container > :nth-child(3), .grid-container > :nth-child(4) { display: none; } .truncate { max-width: 200px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } } </style> <div class="w-full max-w-[500px] mx-auto sm:w-[500px] text-center bg-gray-400 mb-4">Balancete</div> <div class="bg-gray-100 flex flex-col items-center justify-center w-full mx-auto"> <div class="container mx-auto"> <div class="grid-container bg-gray-800 text-white"> <div class="py-0 text-center truncate">Conta</div> <div class="py-0 text-center">Início</div> <div class="py-0 text-center">Débito</div> <div class="py-0 text-center">Crédito</div> <div class="py-0 text-center">Saldo</div> </div> <?php foreach($jMatriz as $conta): ?> <div class="grid-container bg-white"> <div class="border px-4 py-0 text-left truncate"><?=$conta->conta?> <?=$conta->descricao?></div> <div class="border px-4 py-0 text-right"><?=dec($conta->inicio)?></div> <div class="border px-4 py-0 text-right"><?=dec($conta->debito)?></div> <div class="border px-4 py-0 text-right"><?=dec($conta->credito)?></div> <div class="border px-4 py-0 text-right"><?=dec($conta->saldo)?></div> </div> <?php endforeach; $paginaAnterior=$paginaAtual-1; $paginaAtual++; ?> <div class="flex justify-between w-full max-w-[835px] mt-4 mx-auto"> <a href="?Balancete.inicio.<?=$paginaAnterior?>" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-2 rounded">Anterior</a> <a href="?Balancete.inicio.<?=$paginaAtual?>" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-2 rounded">Próximo</a> </div> </div> </div>
  4. O código a seguir consegui com o Copilot. Eu não consegui deixar azul o <div> que contém a palavra balancete. O Copilot me aconselhou a limpar o histórico do navegador, consegui definir a cor do fundo mas não consegui centralizar a palavra balancete no <div>. O Copilot acredita que existe um erro estrutural no código. Eu suponho que defini o <div> principal como 550px, mas a soma das outras colunas dá bem mais do que isso, e assim o Tailwinds não consegue executar o serviço como esperado. Mas a verdade é que eu nem sei o que é a estrutura de um CSS. O mais bacana mesmo é como o Copilot define o tamanho de cada <div> usando o recurso do CSS dentro do marcador <style>, pela primeira vez em cinco anos, consigo definir um tamanho para a primeira coluna e um tamanho para outras quatro. *** depois que publiquei essa mensagem é que eu vi um grave erro de digitação, escrevi "continer", quando o correto é "container". Será esse o famoso erro estrutural que o Copilot comentou? *** balanceteView.php <?php include('menuView.php'); ?> <style> .grid-container {display:grid;grid-template-columns:260px repeat(4,140px)}</style> <div class="bg-gray-100 flex items-center justify-center w-[550px] mx-auto"> <div class="continer mx-auto"> <div class="grid-container bg-blue-700 text-center text-white">Balancete</div> <div class="grid-container bg-gray-800 text-white"> <div class="py-0 text-center">Conta</div> <div class="py-0 text-center">Início</div> <div class="py-0 text-center">Débito</div> <div class="py-0 text-center">Crédito</div> <div class="py-0 text-center">Saldo</div> </div> <?php foreach($jMatriz as $conta): ?> <div class="grid-container bg-white"> <div class="border px-4 py-0"><?=$conta->conta?> <?=$conta->descricao?></div> <div class="border px-4 py-0 text-right"><?=dec($conta->inicio)?></div> <div class="border px-4 py-0 text-right"><?=dec($conta->debito)?></div> <div class="border px-4 py-0 text-center">crédito</div> <div class="border px-4 py-0 text-center">saldo</div> </div> <?php endforeach; $paginaAnterior=$paginaAtual-1; $paginaAtual++; ?> </table> <div class=py-2></div> <a href=?Balancete.inicio.<?=$paginaAnterior?> class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-2 rounded">Anterior</a> <a href=?Balancete.inicio.<?=$paginaAtual?> class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-2 rounded">Próximo</a> </div> </div> </div>
  5. A Gemini ofereceu vários exemplos que não deram certo. A culpa não é dela. Eu é que não consegui ser objetivo na consulta. Na última tentativa eu escrevi assim:tenho 3 itens no nav, o do meio queria que fosse um dropdown, tudo com o tailwinds E só assim consegui montar o código seguinte: arquivo menuView.php <link rel=stylesheet href=output.css> <nav class="bg-gray-800 w-[500px] mx-auto"> <div class="container mx-auto flex justify-between px-4 py-2 text-white"> <div>Tailwinds</div> <div class="relative" onclick="menuDiv.classList.toggle('hidden')">Menu <div id=menuDiv class="hidden absolute mt-2 bg-white rounded-md shadow-lg"> <a href="?Balancete.inicio" class="block px-4 py-2 text-blue-700 hover:bg-blue-100"> Balancete</a> </div> </div> <div class="relative" onclick="loginDiv.classList.toggle('hidden')"><?=$_SESSION['nome']?> <div id=loginDiv class="hidden absolute mt-2 bg-white rounded-md shadow-lg"> <a href="?Login.sair" class="block px-4 py-2 text-blue-700 hover:bg-blue-100"> Sair</a> </div> </div> </div> </nav>
  6. Eu perdi uma tabela inteira de dados. Eu fiquei indignado. Depois de quatro horas de pesquisa, descobri que o mysqli não é a mesma coisa que PDO! Olha só: <?php // mysql.teste.tbdiario(contad varchar)('410') $mysqli=new mysqli("localhost","root","","teste"); $contad=$mysqli->query("select * from tbdiario where docto=1")->fetch_assoc()['contad']; var_dump($contad); // string '410' $pdo=new PDO("mysql:host=localhost;dbname=teste","root",""); $contad=$pdo->query("select * from tbdiario where docto=1")->fetch(PDO::FETCH_OBJ)->contad; var_dump($contad); // int 410
  7. Eu defini o registro indesejável como todo registro que está na tabela conta corrente que não que tem a conta '130' ou '211' correspondente na tabela diário. Botar isso na sintaxe MySQL é um pesadelo. Mas a sintaxe PHP é bem mais fácil: <?php $pendencia=$mysqli->query("select * from tbcontacorrente join tbdiario on tbdiario.docto = tbcontacorrente.docto where pgto = 0") ->fetch_all(MYSQLI_ASSOC); foreach($pendencia as $p) { $eliminar=($p['contad']!=='130')+($p['contad']!=='211')+($p['contac']!=='130')+($p['contac']!=='211'); if($eliminar==4) { echo "<br>eliminar docto ". $p['docto']; } }
  8. Valeu! Eu ainda estou bem longe do ambiente servidor-cliente, eu uso o famoso método científico da tentativa e erro. Aqui no notebook, eu tenho que usar "localhost/meuprojeto" para rodar o projeto. Para rodar no hostinger, eu escrevo meuendereco.com, e ele aparece. Não tenho a menor ideia de como isso funciona, mas que eu acho isso bacana, isso eu acho.
  9. Isso é coisa que eu ainda não tenho solução, mas por enquanto eu faço assim: return echo("Mensagem Enviada"); ou seja, quando o PHP termina de fazer uma tarefa, eu uso o PHP para notificar o usuário. Bem que eu queria usar o JavaScript, mas comigo nunca funcionou. Mas tem hora que o PHP não funciona, tipo header("location:vaParaLa.php"), e aí eu peço ajuda para o JavaScript echo "<script>location.replace('vaParaLa.php')</script>". Eu simplesmente não entendo.
  10. Hahahahaha... eu estava pensando assim: showAlert($sendSuccessMessage, 'success'); exit;
  11. Eu apanho muito com esse negócio de JavaScript versus PHP. A minha intuição me diz para você experimentar o "exit;" na última instrução.
  12. Fase 2: aqui inclui o saldo inicial de cada conta, e também introduzi o Tailwinds no PHP. Usei o tutorial em https://tailwindcss.com/docs/installation - eles presumem que você vai utilizar um subdiretório chamado /src/, mas coloquei tudo no diretório raiz. Os principais arquivos ficaram assim: input.css @tailwind base; @tailwind components; @tailwind utilities; tailwind.config.js /** @type {import('tailwindcss').Config} */ module.exports = { content: ["*.{php,js}"], theme: { extend: {}, }, plugins: [], } Para ativar o servidor do Tailwinds, usei esse comando: npx tailwindcss -i input.css -o output.css --watch E o meu arquivo principal ficou assim: balancete.php <?php $mysqli=new mysqli("localhost","root","","teste"); function dec($value) { return ($value) ? number_format($value,2,',','.') : null; } class Balancete { function inicio() { $rota=explode("_",key($_GET)); $metodo=$rota[0]; $argumento=$rota[1]; return $this->$metodo($argumento); } function balancete($paginaAtual=null) { global $mysqli; $primeiroDia='2024-10-01'; $ultimoDia='2024-10-31'; $matriz=[]; $registros=$mysqli->query("select count(*) as total from tbconta") ->fetch_assoc()['total']; $registrosPorPagina=20; $paginaAtual = ($paginaAtual) ? $paginaAtual : 1; $indicador = ($paginaAtual - 1) * $registrosPorPagina; $contas=json_decode(json_encode( $mysqli->query("select * from tbconta limit $indicador, $registrosPorPagina") ->fetch_all(MYSQLI_ASSOC))); foreach($contas as $conta) { $debitos=$mysqli->query("select sum(valor) as soma from tbdiario where contad=$conta->conta and dia < '$primeiroDia'")->fetch_assoc()['soma']; $creditos=$mysqli->query("select sum(valor) as soma from tbdiario where contac=$conta->conta and dia < '$primeiroDia'")->fetch_assoc()['soma']; $inicio=round($debitos-$creditos,2); $matriz[]=['conta'=>$conta->conta,'descricao'=>$conta->descricao,'inicio'=>$inicio]; } $jMatriz=json_decode(json_encode($matriz)); ?> <link rel="stylesheet" href="output.css"> <div class='w-[500px] mx-auto'> <div class="bg-blue-500 text-white">Balancete</div> <div class="flex"> <div class="w-1/6 p-0 font-bold">Conta</div> <div class="w-1/2 p-0 font-bold">Descrição</div> <div class="w-1/6 p-0 font-bold text-right">Início</div> </div> <?php foreach($jMatriz as $conta): ?> <div class="flex"> <div class="w-1/6 p-0"><?=$conta->conta?></div> <div class="w-1/2 p-0 whitespace-nowrap"><?=$conta->descricao?></div> <div class="w-1/6 p-0 text-right"><?=dec($conta->inicio)?></div> </div> <?php endforeach; $paginaAnterior=$paginaAtual-1; $paginaAtual++; ?> </table> <div class=py-2></div> <a href=?balancete.<?=$paginaAnterior?> class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-2 rounded">Anterior</a> <a href=?balancete.<?=$paginaAtual?> class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-2 rounded">Próximo</a> </div> <?php } } (new Balancete)->inicio();
  13. Ainda não dominei a ferramenta Livewire do Laravel, mas eu gostei dele. O Livewire me lembra os primeiros anos que comecei a engatinhar no PHP, quando não sabia como separar o PHP do HTML. Apesar de não saber como usar o Livewire, ele me ensinou que o Eloquent tem uma paginação embutida, ou seja, você não precisa do Livewire para paginar. O Eloquent tem o paginador embutido. Esse não é o caso do mysqli, mas a Gemini provou que ele tem um paginador embutido. Ele está depois do comando limit: ** o roteador que foi improvisado no método inicio só serve para esse exemplo em particular ** index.php <?php header('location:balancete.php?balancete_1'); balancete.php <?php $mysqli=new mysqli("localhost","root","","teste"); class Balancete { function inicio() { $rota=explode("_",key($_GET)); $metodo=$rota[0]; $argumento=$rota[1]; return $this->$metodo($argumento); } function balancete($paginaAtual=null) { global $mysqli; $registros=$mysqli->query("select count(*) as total from tbconta") ->fetch_assoc()['total']; $registrosPorPagina=10; $paginaAtual = ($paginaAtual) ? $paginaAtual : 1; $indicador = ($paginaAtual - 1) * $registrosPorPagina; $contas=json_decode(json_encode( $mysqli->query("select * from tbconta limit $indicador, $registrosPorPagina")->fetch_all(MYSQLI_ASSOC))); ?> <table><th>Conta<th>Descricao <?php foreach($contas as $conta): ?> <tr><td><?=$conta->conta?><td><?=$conta->descricao?> <?php endforeach; $paginaAnterior=$paginaAtual-1; $paginaAtual++; ?> </table> <a href=?balancete.<?=$paginaAnterior?>>Anterior</a> <a href=?balancete.<?=$paginaAtual?>>Próximo</a> <?php } } (new Balancete)->inicio();
  14. Frank K Hosaka

    O apóstrofo

    Sem querer, eu digitei um apóstrofo dentro da caixa de consulta, e isso acabou gerando uma mensagem de erro. A Gemini sugeriu mudar o meu código pdo->query( ) para pdo->prepare( ), mas isso não resolveu o problema. Então a Gemini sugeriu usar a função PHP addslashes. Eu não tive mais nenhuma mensagem de erro, mas também não tive nenhum resposta na consulta. Assim, chegou a minha vez de improvisar, eu pedi para o PHP excluir qualquer apóstrofo que encontrar no critério assim: function historico() { $criterio=str_replace("'",'',(str_replace(' ','%',$_POST['hist']))); $hist=(new Conn)->select("* from tbdiario where hist like '%$criterio%'"); return view('diarioHistorico',['hist'=>$hist]); }
  15. Baseado no código do counter, tentei montar o pagination. Recebi dezenas de mensagens de erro, e acabou prevalecendo a minha improvisação. Não tenho a menor ideia como usar o Livewire. Para piorar, eu não consegui utilizar o CSS Tailwinds e nem o CSS convencional. Isso é muito chato: routes > web.php <?php use Illuminate\Support\Facades\Route; Route::middleware(['auth', 'verified'])->group(function () { Route::view('counter','counter'); Route::view('pagination','pagination'); }); resources > views > pagination.blade.php <x-app-layout> <div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8"> <livewire:pagination /> </div> </x-app-layout> resources > views > livewire > pagination.blade.php <?php namespace App\Http\Livewire; use Livewire\Volt\Component; use Livewire\WithPagination; use App\Models\tbprod; new class extends Component { public $page=1; public $last_page; public $paginas; public $produtos; use WithPagination; function mount() { $this->paginas=tbprod::paginate(10,['*'],'page',$this->page)->toArray(); $this->last_page=$this->paginas['last_page']; $this->produtos=$this->paginas['data']; } function increment() { if($this->page<$this->last_page) { $this->page++; return $this->mount(); } } function decrement() { if($this->page>1) { $this->page--; return $this->mount(); } } } ?> <div> @foreach($produtos as $produto) <div> {{$produto['codprod']}} {{$produto['prod']}} </div> @endforeach <p><h1>Página Atual: {{$page}}</h1></p> <button wire:click="increment"> Próximo </button> <button wire:click="decrement"> Anterior </button> </div> Em tempo, esqueci de executar npm run dev.
  16. Eu tentei estudar a paginação no Livewire com a Gemini, mas não consegui. Decidi usar o velho motor de busca do Google, e acabei entrando nesse tutorial: https://livewire.laravel.com/docs/quickstart Ele tenta explicar o que é LiveWire e mostra um código exemplo para mostrar como ele funciona. Só que ele não funcionou. E assim eu desisti do Laravel milhares de vezes, por não conseguir encontrar nenhum tutorial que funcionasse. Mas, nesse ano as coisas são diferentes. Eu consegui executar o tutorial do Chirp com o LiveWire, ele não é fácil de entender; mesmo assim, tentei usar o princípio científico da tentativa e erro e tentei fazer o counter funcionar. E eu consegui! routes > web.php <?php use Illuminate\Support\Facades\Route; Route::middleware(['auth', 'verified'])->group(function () { Route::view('counter','counter'); }); resources > views > counter.blade.php <x-app-layout> <div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8"> <livewire:counter /> </div> </x-app-layout> resources > views > livewire > counter.blade.php <?php use Livewire\Volt\Component; new class extends Component { public $count=1; function increment(){$this->count++;} function decrement(){$this->count--;} } ?> <div> <h1>{{$count}}</h1> <button wire:click="increment">+</button> <button wire:click="decrement">-</button> </div>
  17. Eu ainda tenho muita dificuldade para trabalhar com o marcador <div> e mais ainda com o CSS Tailwinds, mas com a ajuda da Gemini consegui montar a minha tabela à base de <div>, e aos poucos vou ingressando no mundo "blade" do Laravel: resources > views > diario.blade.php <x-app-layout> <div class='w-[500px] mx-auto'> <div class="flex"> <div class="w-1/4"> <form method=post action=diarioDia> @csrf <input type=date name=dia value='{{ $lctos[0]->dia }}' onchange=submit()> </form> </div> </div> <div class="flex"> <div class="w-1/6 p-0 font-bold">Lcto</div> <div class="w-1/6 p-0 font-bold">CtaD</div> <div class="w-1/6 p-0 font-bold">CtaC</div> <div class="w-1/6 p-0 font-bold">Valor</div> <div class="w-1/4 p-0 font-bold">Hist</div> </div> @foreach($lctos as $lcto) <div class="flex"> <div class="w-1/6 p-0">{{ $lcto->lcto }}</div> <div class="w-1/6 p-0">{{ $lcto->contad }}</div> <div class="w-1/6 p-0">{{ $lcto->contac }}</div> <div class="w-1/6 p-0">{{ $lcto->valor }}</div> <div class="w-1/4 p-0 whitespace-nowrap">{{ $lcto->hist }}</div> </div> @endforeach </div> </x-app-layout>
  18. Não é a primeira vez que eu enfrento o erro do sql_mode, quando executo o comando $codp=tbhistprod::groupBy('codp')->get(); Só que eu não lembrava como eu resolvi, eu só sei que não mexi na configuração do MySQL. Pedi ajuda da Gemini, fiz várias tentativas e erros, e acabei entrando no modo desespero. Respirei um pouco, e decidi entrar no terminal do MySQL e tentei montar a consulta: Select codp from tbhistprod group by codp Foi nesse momento que eu percebi o meu erro no Laravel, lá eu pedi implicitamente para pegar todos os campos mas agrupar apenas um campo, e hoje isso não é mais possível. Para corrigir o erro, eu fiz assim no Laravel: $codp=tbhistprod::select('codp')->groupBy('codp')->get();
  19. Hoje estudei um pouco sobre validação, mas não queria usar o navegador, usei o terminal, ao invés de php artisan serve, usei o php artisan tinker. a função é essa daqui: <?php namespace App\Http\Controllers; use Illuminate\Http\Request; class Diario { function teste(Request $request) { $dataValida = $request->validate(['dob' => [ 'required','date', 'before_or_equal:' . now()->subYears(18)->format('Y-m-d')]]); return $dataValida; } } Depois de ativar o php artisan tinker, digitei o seguinte no terminal (new App\Http\Controllers\Diario)->teste(new Illuminate\Http\Request(['dob'=>'2006-09-28'])); Para chegar nessa sintaxe fiz várias consultas com a Gemini, e também um monte de tentativa e erro, mas eu gostei, bem mais prático do que mexer no web.php e ativar o server.
  20. Eu queria consultar um produto pelo seu código, ou pelo código de barra, ou pelo código do fornecedor, além da famosa descrição. A sugestão da Gemini foi de concatenar os campos. A sugestão não deu certo. Usei o terminal do MySQL e descobri que o produto que eu procurava não tinha código de barra ou o código do fornecedor, e isso acabou anulando a função de concatenar. Para evitar esse contratempo, a Gemini sugeriu usar a função coalesce, assim: app > Http > Controllers > Produto.php <?php // ... function filtra(Request $request) { $criterio=str_replace(' ','%',$request->procura); session(['criterio'=>$criterio]); $produtos=tbprod::whereRaw("concat(prod,'',codprod,'',coalesce(codbar,''),'', coalesce(codforn,'')) like '%$criterio%'")->get(); return view('produtoView',['produtos'=>$produtos]); }
  21. Frank K Hosaka

    Pagina Expirar

    Encontrei isso com a Gemini: <?php session_start(); // Verifica se a sessão já existe if (isset($_SESSION['last_activity'])) { // Calcula o tempo de inatividade em segundos $time_elapsed = time() - $_SESSION['last_activity']; // Define o tempo limite em segundos (5 minutos neste caso) $timeout_duration = 300; // Se o tempo de inatividade exceder o limite, destrói a sessão e redireciona if ($time_elapsed >= $timeout_duration) { session_unset(); session_destroy(); header("Location: login.php"); // Redireciona para a página de login } } // Atualiza o timestamp da última atividade $_SESSION['last_activity'] = time(); // Resto do seu código PHP
  22. Em 2022, não existia a Gemini, o Copilot e tantos outros serviços de Inteligência Artificial. Assim, para eu ajuntar duas tabelas no Laravel, tive que usar a classe DB. Aqui em 2024, mostrei o model do tbhistprod para a Gemini: <?php // app > Models > tbhistprod.php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class tbhistprod extends Model { use HasFactory; protected $table="tbhistprod"; const UPDATED_AT=null; const CREATED_AT=null; protected $fillable=['codprod','dia','docto','qt','custototal','codp','lcto','pessoa']; public function produtos() { return $this->belongsTo(tbprod::class,'codprod'); } public function pessoa() { return $this->belongsTo(tbpessoa::class,'codp'); } } Perguntei para ela como ajuntar a tbhistprod com a tbprod pelo Eloquent, e aqui a resposta: <?php // app > Http > Controllers / Estoque.php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\tbdiario; use App\Models\tbentraprod; use App\Models\tbhistprod; use App\Models\tbpessoa; use App\Models\tbprod; class Estoque { function teste() { $entrada=tbdiario::where('contad',123)->sum('valor'); $verificar=tbhistprod::with('produtos') ->whereHas('produtos',function($query) {$query->where('loc','<>','a24');}) ->where('custototal','>',0) ->sum('custototal'); return "entrada $entrada <br> verificar $verificar"; } //... }
  23. Frank K Hosaka

    Problemas com rotas

    Eu usei a pasta a Astudy para testar o seu código, veja se o seu arquivo .htaccess (que fica na raiz do projeto como o index.php) está mais ou menos assim: # Ativação do RewriteEngine que nos permite gerenciar as rotas RewriteEngine On # Definição da rota principal RewriteBase / # Se o diretório ou arquivos digitados na URL não existirem, seguir a RewriteRule RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f # Rewrite Rule, redirecionar todas as requests para o index.php RewriteRule ^(.+)$ /Astudy/index.php [QSA,L] No index.php utilizei um autload que você não listou, e também modifiquei a rotina original <?php spl_autoload_register(function ($class) { $file = __DIR__ . '/app/controllers/' . $class . '.php'; if (file_exists($file)) { require_once $file; } }); require 'rotas.php'; try{ $pos=strrpos($_SERVER['REQUEST_URI'],'/'); $uri=substr($_SERVER['REQUEST_URI'],$pos); $request=$_SERVER['REQUEST_METHOD']; if(!isset($router[$request])) { throw new Exception('A rota não existe0'); } if(!array_key_exists($uri,$router[$request])) { throw new Exception('A rota não existe1'); } $controller=$router[$request][$uri]; $controller(); }catch(Exception $e) { echo "". $e->getMessage() .""; } E aqui rotas.php <?php function load($controller,$action) { try { // se controller existe if (!class_exists($controller)) { throw new Exception("O controller {$controller} não existe"); } $controllerInstance = new $controller(); if (!method_exists($controllerInstance, $action)) { throw new Exception( "O método {$action} não existe no controller {$controller}" ); } $controllerInstance->$action(); } catch (Exception $e) { echo $e->getMessage(); } } $router=[ "GET" => [ "/" => fn () => load("HomeController", "index"), "/info" => fn () => load("InfoController", "info"), ], "POST" => [ //"/info" => fn () => load("InfoController", "info"), ], ]; Espero que tenha ajudado. Eu gostei desse código, ele se aproxima bastante do modelo Laravel. Eu tenho o PHP 8.2, um autoload e um roteador bem safado que dispensa o uso de pastas, coloco tudo no diretório raiz, não uso o arquivo .htaccess e não preciso atualizar o arquivo rotas.php (aliás, eu nem tenho esse arquivo) toda vez que eu criar uma tarefa nova, aqui está ele, para usá-lo, eu uso a sintaxe ?classe.metodo.argumento: arquivo index.php <?php spl_autoload_register(fn ($class) => require str_replace('\\', DIRECTORY_SEPARATOR, strtolower($class)) . '.php'); $rota='login_login'; if($_GET) { if(strpos(key($_GET),"_")==0) { exit; } $rota=isset($_GET) ? key($_GET) : $rota; } $segmentos=explode('_',$rota); $nomeControle=$segmentos[0] ?? 'login'; $metodo=$segmentos[1] ?? 'login'; $parametro=$segmentos[2] ?? null; $controle=new $nomeControle(); $controle->$metodo($parametro); arquivo login.php <?php class Login { function login() { ?> olá mundo! <br> <form method=post action=?login.maisExemplo> <input type=submit value="Me clique"> </form> <?php } function maisExemplo() { echo "E aí, você gostou?"; } }
  24. Você esqueceu de colocar o script completo. Aqui um exemplo de como você pode expor o problema: Parse error: syntax error, unexpected token "?" in C:\wamp64\www\Astudy\index.php on line 28 File: index.php 01: <?php 02: class Teste 03: { 04: function comecarDeNovo() 05: { 06: ?> 07: <p> 08: <form method=post action=index.php> 09: <input type=submit value='Começar de novo'> 10: </form> 11: <?php 12: exit; 13: } 14: function inicio() 15: { 16: ?> 17: conteúdo do $_GET : 18: <?=var_dump($_GET)?> 19: conteúdo do $_POST : 20: <?=var_dump($_POST)?> 21: <?php 22: return $this->comecarDeNovo(); 23: } 24: 25: function mensagem($problema) 26: { 27: 28: Rota <?=json_encode($problema)?> inválida! 29: <?php 30: return $this->comecarDeNovo(); 31: } 32: function naoFazerNada() 33: { 34: 35: } 36: 37: } 38: spl_autoload_register(fn ($class) => 39: require str_replace('\\', DIRECTORY_SEPARATOR, strtolower($class)) . '.php'); 40: $rota='Teste_naoFazerNada'; 41: if($_GET) 42: { 43: if(strpos(key($_GET),"_")==0) 44: { 45: return (new Teste)->mensagem($_GET); 46: } 47: $rota=isset($_GET) ? key($_GET) : $rota; 48: } 49: $segmentos=explode('_',$rota); 50: $nomeControle=$segmentos[0]; 51: $metodo=$segmentos[1]; 52: $parametro=$segmentos[2] ?? null; 53: $controle=new $nomeControle(); 54: $controle->$metodo($parametro); 55: ?> 56: <form method=post action=?teste.inicio> 57: <input type=submit name=bacalhau value=Teste> 58: <input type=hidden name=sardinha value=nenhum> 59: </form>
  25. Eu comecei a estudar o PHP em 2020. Os meus códigos estavam bastante embaralhados, PHP aqui, HTML ali, e era difícil consertar o código. Hoje eu sei um pouco sobre classe e imaginei se era possível criar um conjunto de funções sem o autoload e sem o roteador no PHP. A resposta é sim, olha só que beleza: arquivo classe.php <?php class Classe { function roteador() { if(count($_GET)) { $metodo=key($_GET); $parametro=$_GET[$metodo]; return $this->$metodo($parametro); } if(count($_POST)) { $metodo=key($_POST); $parametro=$_POST[$metodo]; return $this->$metodo($parametro); } } } (new Classe)->roteador(); Se você não trabalha com a classe (programação orientada a objeto) não há porque instalar um roteador no PHP, mas nada impede de você trabalhar com a classe no meio dos códigos. Nesse caso, é a classe que vai precisar de um roteador para saber qual a função você precisa utilizar. Vamos supor que exista uma função chamada inicio. Para chamá-lo, você pode usar header('location:classe.php?inicio). No caso acima, essa função não existe. A seguir vou deixar uma lista de uma classe que não tem o suporte de um autoload e um roteador no index.php: arquivo diario.php <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"> </script> <style> @media (min-width: 768px) { body {width: 50%; margin: auto} } @media (max-width: 767px) { body {width: 75%; margin: auto} } a {color:blue;text-decoration:none} a:hover {color:black;} form {margin:0} .inv {border:none;background:transparent;font-weight:600} .linha {line-height:0px} summary{list-style:none} td {white-space: nowrap} </style> <?php session_start(); $mysqli=new mysqli("localhost","root","","teste"); date_default_timezone_set('America/Sao_Paulo'); function dbr($date) { return date('d/m/y',strtotime($date)); } function dec($value) { return ($value) ? number_format($value,2,',','.') : null; } function deca($num) { $value=str_replace(".","",$num); return str_replace(",",".",$value); } class Diario { function roteador() { if(count($_GET)) { $metodo=key($_GET); $parametro=$_GET[$metodo]; return $this->$metodo($parametro); } if(count($_POST)) { $metodo=key($_POST); $parametro=$_POST[$metodo]; return $this->$metodo($parametro); } } function inicio() { global $mysqli; $dia=(isset($_SESSION['dia'])) ? $_SESSION['dia'] : date('Y-m-d'); $mensagem=(date('Y-m-d',strtotime($dia))<>date('Y-m-d')) ? " hoje é ".date('d/m/Y') : null; $lctos = json_decode(json_encode($mysqli->query("select * from tbdiario where dia = '$dia' order by lcto, docto")->fetch_all(MYSQLI_ASSOC))); $somaDebito=$mysqli->query("select sum(case when contad>0 then valor else 0 end) as soma from tbdiario where dia = '$dia'")->fetch_assoc()['soma']; $somaCredito=$mysqli->query("select sum(case when contac>0 then valor else 0 end) as soma from tbdiario where dia = '$dia'")->fetch_assoc()['soma']; ?> <table class='table table-striped'> <tr class=fw-semibold> <td colspan=5> <form method=post action=diario.php> <input type='submit'name=lancamento value='Lançamentos' size='8'> do dia <input id=data type=date size=6 name=dia value=<?=$dia?> onchange=submit()><?=$mensagem?> </form> <tr class=fw-semibold><td>Lcto<td>Ctad<td>Ctac<td class=text-end>Valor <td> <form method=post action=diario.php> <input name=historico onchange=submit() autocomplete=off placeholder='Procurar no histórico'> </form> <?php foreach($lctos as $lcto): ?> <tr class=linha> <td><?=$lcto->lcto?> <td><?=$lcto->contad?> <td><?=$lcto->contac?> <td class=text-end><?=dec($lcto->valor)?> <td><?=$lcto->hist?> <?php endforeach; ?> <tr class=fw-semibold><td><td><td><td class=text-end><?=dec($somaDebito)?><td> <?php if($somaCredito!==$somaDebito): ?> <td class='text-end text-danger'><?=dec($somaCredito)?> Total de crédito <?php else: ?> </table></div> <?php endif; } function historico($hist) { global $mysqli; $historico = str_replace(' ','%',$hist); $lctos=json_decode(json_encode($mysqli->query("select * from tbdiario where hist like '%$historico%'")->fetch_all(MYSQLI_ASSOC))); ?> Lançamentos com o histórico <?=$hist?> <table class='table table-striped linha'> <tr><th>Dia<th>Lçto<th>CtaD<th>CtaC<th>Valor<th>Histórico <?php foreach($lctos as $lcto): ?> <tr> <td><?=dbr($lcto->dia)?> <td><?=$lcto->lcto?></a> <td><?=$lcto->contad?> <td><?=$lcto->contac?> <td class=text-end><?=dec($lcto->valor)?> <td><?=$hist?> <?php endforeach; ?> </table> <?php } function registro() { global $mysqli; $dia=$_GET['registro']; $contad = empty($_GET['debito']) ? 'null' : $_GET['debito']; $contac = empty($_GET['credito']) ? 'null' : $_GET['credito']; $lcto=$_GET['lcto']; $valor= empty($_GET['valor']) ? 'null' : deca($_GET['valor']); $hist=$mysqli->real_escape_string($_GET['hist']); $mysqli->query("insert into tbdiario (lcto,dia,contad,contac,valor,hist) values ($lcto,'$dia',$contad,$contac,$valor,'$hist')"); return $this->inicio(); } function lancamento() { global $mysqli; $dia=$_SESSION['dia']; //plano de contas $ativo=json_decode(json_encode($mysqli->query("select * from tbconta where conta < 201")->fetch_all(MYSQLI_ASSOC))); $passivo=json_decode(json_encode($mysqli->query("select * from tbconta where conta >=201")->fetch_all(MYSQLI_ASSOC))); $contaPassivo=count($passivo); $proximoLcto=$mysqli->query("select lcto from tbdiario order by lcto desc") ->fetch_assoc()['lcto']+1; ?> <script> btmenu.innerHTML='Lançamento' document.title='Lançamento' var idControle,Descricao function ir(controle,destino) { idControle=controle Descricao=destino } function voltar(texto) { controle=document.getElementById(idControle) destino=document.getElementById(Descricao) controle.value=texto.substr(0,3) tamanho=texto.strlen destino.innerHTML=texto.substr(4,tamanho) } </script> <div class=modal id=myModal> <div class=modal-dialog> <div class=modal-content> <div class=modal-body> <table class='table table-striped linha'> <?php foreach($ativo as $key=>$row): ?> <tr><td><a href data-bs-dismiss='modal' onclick=voltar(this.innerHTML)><?=$row->conta." ".$row->descricao?></a> <?php if($key<$contaPassivo): ?> <td><a href data-bs-dismiss='modal' onclick=voltar(this.innerHTML)><?=$passivo[$key]->conta." ".$passivo[$key]->descricao?></a> <?php else: ?> <td> <?php endif; ?> <?php endforeach; ?> </table> </div> </div> </div> </div> <form> <div> <table class='table table-sm table-striped'> <tr><td>Lançamento<td><?=$proximoLcto?> <tr><td>Data<td><?=dbr($dia)?> <input type='hidden' name='registro' value='<?=$dia?>'> <input type='hidden' name='lcto' value=<?=$proximoLcto?>> <tr><td>ContaD<td><input id=idebito name=debito onclick="ir(id,'adebito')" data-bs-toggle=modal data-bs-target=#myModal size=2 autocomplete=off> <a id=adebito></a> <tr><td>ContaC<td><input id=icredito name=credito onclick="ir(id,'acredito')" data-bs-toggle=modal data-bs-target=#myModal size=2 autocomplete=off> <a id=acredito></a> <tr><td>Valor<td><input name='valor' id='valor' autocomplete='off' onchange='hist.focus()'> <tr><td>Histórico<td><input name='hist' id='hist' size='30' autocomplete='off' required> <tr><td><td><input type=submit value=Confirmar></table></div> </form> <?php } function dia($dia) { $_SESSION['dia']=$dia; $this->inicio(); } } (new Diario)->roteador(); ?>
×
×
  • Criar Novo...